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?
The following works lists all
*.txt
files in the current dir, except those that begin with a number.This works in
bash
,dash
,zsh
and all other POSIX compatible shells.In line one the pattern
/some/dir/*.txt
will cause thefor
loop to iterate over all files in/some/dir
whose name end with.txt
.In line two a case statement is used to weed out undesired files. – The
${FILE##*/}
expression strips off any leading dir name component from the filename (here/some/dir/
) so that patters can match against only the basename of the file. (If you're only weeding out filenames based on suffixes, you can shorten this to$FILE
instead.)In line three, all files matching the
case
pattern[0-9]*
) line will be skipped (thecontinue
statement jumps to the next iteration of thefor
loop). – If you want to you can do something more interesting here, e.g. like skipping all files which do not start with a letter (a–z) using[!a-z]*
, or you could use multiple patterns to skip several kinds of filenames e.g.[0-9]*|*.bak
to skip files both.bak
files, and files which does not start with a number.The
extglob
shell option gives you more powerful pattern matching in the command line.You turn it on with
shopt -s extglob
, and turn it off withshopt -u extglob
.In your example, you would initially do:
The full available extended globbing operators are (excerpt from
man bash
):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:Of course, normal shell globing works, so the last example could also be written as:
My personal preference is to use grep and the while command. This allows one to write powerful yet readable scripts ensuring that you end up doing exactly what you want. Plus by using an echo command you can perform a dry run before carrying out the actual operation. For example:
will print out the files that you will end up copying. If the list is correct the next step is to simply replace the echo command with the copy command as follows:
A trick I haven't seen on here yet that doesn't use
extglob
,find
, orgrep
is to treat two file lists as sets and "diff" them usingcomm
:comm
is preferable overdiff
because it doesn't have extra cruft.This returns all elements of set 1,
ls
, that are not also in set 2,ls *Music*
. This requires both sets to be in sorted order to work properly. No problem forls
and glob expansion, but if you're using something likefind
, be sure to invokesort
.Potentially useful.
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
this would do it excluding exactly 'Music'
this and that for excluding things like Music?* or *?Music