21

I'm not very familiar with all the tricks of grep/find/awk/xargs quite yet.

I have some files matching a particular pattern, say *.xxx. These files are in random places throughout a certain directory. How can I find all such files, and move them to a folder in my home directory on Unix (that may not exist yet)?

  • 4
    You've got to take care when talking about "file type". In unixy environments, the ".xxx" example isn't even an extension in the Windows sense. ".xxx" just constitutes a suffix of the file name. "File type" is more one of a few categories: regular file, device file, symbolic link, directory, named pipe, Unix-family socket, maybe a few others. – Bruce Ediger Feb 2 '12 at 22:13
  • See also: unix.stackexchange.com/questions/7027/… – jasonwryan Feb 2 '12 at 22:16
  • @BruceEdiger thanks I guess I really meant "filename pattern" – qodeninja Feb 3 '12 at 1:14
20
mkdir ~/dst
find source -name "*.xxx" -exec mv -i {} -t ~/dst \;
  • 1
    I would use mv -i -t ~/dst {} + – enzotib Feb 3 '12 at 6:56
17

If you want to move all the files inside a directory hierarchy to a single destination directory, in bash ≥4 (put shopt -s globstar in your ~/.bashrc) or zsh:

mkdir ~/new-directory
mv -i **/*.xxx ~/new-directory

In other shells:

mkdir ~/new-directory
find . -name '*.xxx' -exec mv -i {} ~/new-directory \;

How to read this find command:

  • .: traverse the current directory
  • -name '*.xxx': act on files whose name matches this pattern
  • -exec … \;: perform this command on each file, replacing {} by the path to the file

There's a more complex command using find that's faster if you have many files as it doesn't need to invoke a separate mv process for each file:

find . -name '*.xxx' -exec sh -c 'mv -i "$@" "$0"' ~/new-directory {} +

The + at the end tells find to invoke the command on multiple files at a time. Since find can only put the file names at the end of the command line, and mv needs to have the destination directory last, we use an intermediate shell to rearrange the arguments ("$0" is the first argument to the shell, ~/new-directory, and "$@" are the subsequent arguments coming from find's expansion of {}).

4

If you want to replicate the directory structure of the matching source files to the new target directory, you can make use of GNU cp's --parents option:

mkdir /path/to/target_dir
cd source_dir
find . -name '*.xxx' -exec cp -iv --parents -t /path/to/target_dir {} +
2

you can use find without ‍‍-exec‍ as well:

mkdir /path/to/dest    
cp `find /path/to/source -name "*.jar"` /path/to/dest
  • 1
    Note however that find -exec is much safer; the above will fail on file names containing white space, for example. – dhag Apr 16 '15 at 14:30

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.