I created a folder on my home directory call junk, and let's say I want to move all .cpp and .h files to it. How would I do it? My first thought is to start with find ~ -name *.cpp -print, but I don't know how to put in multiple patterns into the find argument, and I'm fairly lost after that.



cd &&
  find . -path ./junk -prune -o -type f \( \
    -name '*.h' -o -name '*.cpp' \) -exec sh -c '
      exec mv -i "$@" junk' sh {} +

Above excluding the junk folder itself from the search.

We're only removing regular files (-type f). There may be other types of files you want to move like symlinks, but beware that moving symlinks often break them.

The -i is a safeguard to avoid two files with the same name overriding each other.

  • please once check my updated answer, I think I have wrongly explain regex part – Rahul Patil Feb 8 '14 at 11:57
  • Could you please explain the extra calls to sh? As opposed to for instance find . ! -path './junk/*' -type f \( -name '*.h' -o '*.cpp' \) -exec mv -i "{}" ./junk/ \; – grebneke Feb 8 '14 at 12:12
  • @grebneke, mv -i {} junk \; would run one mv per file. Using + means pass as may files as possible. You need sh to be able to have a junk argument after that list. With GNU or FreeBSD mv, you could have done -exec mv -it junk {} + instead. – Stéphane Chazelas Feb 8 '14 at 12:43
  • @StephaneChazelas - I see, but there are two sh, what does the second one do sh {} +? – grebneke Feb 8 '14 at 13:13
  • @grebneke, the first argument after sh -c code is for $0 (used for error messages...), "$@" starts after. – Stéphane Chazelas Feb 8 '14 at 14:44

If on a GNU system, you can use the -regex option to find as shown below:

find . -regex ".*\.\(h\|cpp\)" -exec echo mv -v "{}" ~/junk \;

the output will show which command would be executed, like a dry run. If that looks good, you can remove the echo for applying.

Command Break Down

  • -regex : File name matches regular expression pattern, the default regex type it's uses emacs
  • ".*\.\(h\|cpp\)" : Since it's uses default regex type emacs, as per pattern match . (dot) means matches any character so to match exact . ( dot), we have to use escape character that is \. means for special character like (, | we have to use escape character. the pattern same as .*.(h|cpp) (regextype posix-egrep )
  • -exec : Execute command
  • { } : The string { } replaced by the matches file name
  • \; : Needs to be there as it tells the end of arguements provided to -exec variable

For more information on regular expression you can refer

  • can you break down what ".*\.(h\|cpp)" means? I'm a beginner so I'm completely lost. – Jonathan Chiou Feb 8 '14 at 11:33
  • @JonathanChiou See the updated answer.. – Rahul Patil Feb 8 '14 at 11:50

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.