Say I want to copy the contents of a directory excluding files and folders whose names contain the word 'Music'.
cp [exclude-matches] *Music* /target_directory
What should go in place of [exclude-matches] to accomplish this?
Say I want to copy the contents of a directory excluding files and folders whose names contain the word 'Music'.
cp [exclude-matches] *Music* /target_directory
What should go in place of [exclude-matches] to accomplish this?
One solution for this can be found with find.
# mkdir foo bar
# touch foo/a.txt foo/Music.txt
# find foo -type f ! -name '*Music*' -exec cp {} bar \;
# ls bar
a.txt
Find has quite a few options, you can get pretty specific on what you include and exclude.
Edit: Adam in the comments noted that this is recursive. find options mindepth and maxdepth can be useful in controlling this.
Not in bash (that I know of), but:
cp `ls | grep -v Music` /target_directory
I know this is not exactly what you were looking for, but it will solve your example.
You can also use a pretty simple for
loop:
for f in `find . -not -name "*Music*"`
do
cp $f /target/dir
done
In Bash you can do it by enabling the extglob option, like this (replace ls for cp and add the target directory, of course)
~/foobar> shopt extglob
extglob off
~/foobar> ls
abar afoo bbar bfoo
~/foobar> ls !(b*)
-bash: !: event not found
~/foobar> shopt -s extglob #Enables extglob
~/foobar> ls !(b*)
abar afoo
~/foobar> ls !(a*)
bbar bfoo
~/foobar> ls !(*foo)
abar bbar
You can later disable extglob with
shopt -u extglob
If you want to avoid the mem cost of using the exec command, I believe you can do better with xargs. I think the following is a more efficient alternative to
find foo -type f ! -name '*Music*' -exec cp {} bar \; # new proc for each exec
find . -maxdepth 1 -name '*Music*' -prune -o -print0 | xargs -0 -i cp {} dest/
The extglob
shell option gives you more powerful regular expressions in the command line.
You turn it on with shopt -s extglob
, and turn it off with shopt -u extglob
.
In your example, you would initially do:
$ shopt -s extglob
$ cp !(*Music*) /target_directory
The full available _ext_ended _glob_bing operators are (excerpt from man bash
):
If the extglob shell option is enabled using the shopt builtin, several extended pattern matching operators are recognized. In the following description, a pat‐ tern-list is a list of one or more patterns separated by a |. Composite patterns may be formed using one or more of the following sub-patterns:
- ?(pattern-list)
Matches zero or one occurrence of the given patterns- *(pattern-list)
Matches zero or more occurrences of the given patterns- +(pattern-list)
Matches one or more occurrences of the given patterns- @(pattern-list)
Matches one of the given patterns- !(pattern-list)
Matches anything except one of the given patterns
So, for example, if you wanted to list all the files in the current directory that are not .c or .h files, you would do:
$ ls -d !(*@(.c|.h))
Of course, normal shell globing works, so the last example could also be written as:
$ ls -d !(*.[ch])