Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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.

share|improve this question


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.

share|improve this answer
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

share|improve this answer
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 posting your answer, you agree to the privacy policy and terms of service.

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