I'll try to be as specific as possible. I have a Packages folder containing subfolders with various names, but in each of those subfolders there will always be a dist folder. I want to find the folders containing dist, and then move/copy only dist and its parent folder to a new directory.


Current path structure is as below:


NOTE: core-types, graphql, etc., all contain subfolders in addition to dist; otherwise this would be much more straightforward...

I am trying set it up so that when these paths are migrated to a new directory, say, ~/Documents/Artifacts/, it will look like:


Here's the script I hacked together in case someone can offer guidance:

find ~/Documents/Packages -name dist -print \
| sort -u \
      | while read olddir
          moveto="~/Documents/Artifacts/$(echo \"$olddir\" | cut -d\/ -f 6)"
          mv "$olddir" "$moveto"

There has to be a better way to accomplish this...


I don’t mean to be flippant, but you have two issues:

  1. Identifying the subdirectories named dist, and
  2. moving or copying them into the Artifacts directory.

This is quite a bit easier if we use relative pathnames.  If you absolutely need to use absolute pathnames (har har), say so.

Here are two ways to do step 1 (identifying the subdirectories named dist):


cd ~/Documents/Packages &&
find . -name dist -type d -exec sh -c 'for d do parent="${d%/*}"; \
                                                mkdir -p "../Artifacts/$parent"; \
                                                mv "$d" "../Artifacts/$parent"; done' \
                                                sh {} +

(You can put the find command all on one line if you want.)  This goes into ~/Documents/Packages, so we can use relative pathnames.  A fairly straightforward use of the -name and -type tests of find to identify (sub)directories named dist.  Use the -exec action to pass their names to a miniature shell script.

The script loops over its arguments.  For each one, it identifies the parent directory by removing / and a pathname level from the right.  For example, the parent of ./core-types/dist is ./core-types.  (Remember; we are in ~/Documents/Packages and looking at ., so we are seeing relative pathnames.)  I could have said parent="${d%/dist}", but I wanted to keep it generic.  Create the destination/parent directory — for example, ../Artifacts/./core-types.  (The extra ./ is ignored; /./ acts like /, so this creates ../Artifacts/core-types, which is ~/Documents/Packages/../Artifacts/core-types, which is ~/Documents/Artifacts/core-types.)  We then move the dist directory into that directory.

bash Pathname Expansion

This depends on a feature of bash that is not present in all shells.  (For that matter, it might not be in all versions of bash.)

cd ~/Documents/Packages && shopt -s globstar &&
for d in **/dist/; do d="${d%/}"; parent="${d%/*}";
                                  mkdir -p "../Artifacts/$parent";
                                  mv "$d" "../Artifacts/$parent"; done

Set the globstar shell option (shopt), which causes ** to do a recursive search.  Then loop through **/dist/.  If we said **/dist, that would find all files and directories named dist; adding the / at the end constrains the search to (sub)directories only.  For each one, execute a bunch of commands.

**/dist/ gives us the directory names in the form core-types/dist/ (with the / at the end, as we specified).  d="${d%/}" strips off that trailing slash.  The rest of the code is the same.

Note: this will not look under top-level directories whose names begin with . (e.g., ~/Documents/Packages/.memories/dist) unless you add the dotglob option.

Step 2

If you want to copy instead of move, just change mv to cp -R in either of the above commands.


Not sure if you try using if (cat /Documents/package/**/*/dist) then mv or cp

  • 1
    -1. Answers should be specific and clear. This one seems cryptic first, then one notices that it simply makes no sense. E.g. cat-ing directories in Linux doesn't work. – Kamil Maciorowski Aug 6 '19 at 11:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.