It's generally a bad idea to parse the output of ls
or find
, because you can't distinguish which characters are part of a file name and which characters are separators. If you don't control the file names, this can be a security hole, allowing an adversary to craft file names that cause your script to execute arbitrary code. See Why does my shell script choke on whitespace or other special characters?. It may be ok in your case though, especially as your files seem to be some kind of source code tree where it's common to have file names with no “exotic” characters, in particular no spaces.
Still, it isn't really more difficult to use a robust command. The core idea is to make find
invoke mv
instead of parsing the output of find
. The following command moves .xml
from the current directory and subdirectories recursively:
find . ! -type d -name '*.xml' ! -name deposit.xml -exec mv {} ./Archive \;
To speed this up a little, you can group invocations of mv
by running an intermediate shell.
find . ! -type d -name '*.xml' ! -name deposit.xml -exec sh -c 'mv "$@" "$0"' ./Archive {} +
If you meant to move only files from the current directory, without traversing subdirectories, then you need to instruct find
not to recurse. If your find
implementation supports the -maxdepth
option:
find . -maxdepth 1 ! -type d -name '*.xml' ! -name deposit.xml -exec sh -c 'mv "$@" "$0"' ./Archive {} +
Otherwise:
find . -name . -o -type d -prune -o -name '*.xml' ! -name deposit.xml -exec sh -c 'mv "$@" "$0"' ./Archive {} +
If your shell is ksh, you can use its extended globs. This is easier than using find
, but less portable. To move files in the current directory:
mv !(deposit).xml Archive/
In ksh93, to move files from subdirectories as well:
set -o globstar
mv **/!(deposit).xml Archive/
In bash, you can use the !(…)
pattern as well, but you need to run shopt -s extglob
first. To use the **/
pattern, you need to run shopt -s globstar
first, and beware that up to bash 4.2, **/
traverses symbolic links to directories in addition to directories.
shopt -s extglob globstar
mv **/!(deposit).xml Archive/
In zsh, you can use the !(…)
pattern after running setopt ksh_glob
. Alternatively, you can use zsh's syntax for that after running setopt extended_glob
. The recursive traversal syntax is available either way.
setopt extglob
mv **/(^deposit).xml Archive/