I have a folder with a lot of files. I want to copy all files which begin with of these names (separated by space):

abc abd aer ab-x ate

to another folder. How can I do that?

  • so the filename consists of abc abd aer ab-x ate – Avinash Raj Jun 19 '14 at 10:19
  • no begins with them. – user69453 Jun 19 '14 at 10:20

With csh, tcsh, ksh93, bash, fish or zsh -o cshnullglob, you can use brace expansion and globbing to do that (-- is not needed for these filenames, but I assume they are just examples):

cp -- {abc,abd,aer,ab-x,ate}* dest/

If you'd rather not use brace expansion, you can use a for loop (here POSIX/Bourne style syntax):

for include in abc abd aer ab-x ate; do
    cp -- "$include"* dest/

If you have a very large amount of files, this might be slow due to the invocation of cp once per include. Another way to do this would be to populate an array, and go from there (here ksh93, zsh or recent bash syntax):

includes=(abc abd aer ab-x ate)

for include in "${includes[@]}"; do
    files+=( "$include"* )

cp -- "${files[@]}" dest/        
| improve this answer | |
  • She/He said copy (cp) not move (mv) ;) You're too fast :) – Hastur Jun 19 '14 at 10:21
  • In fact I have a much longer list than abc,abd,aer,ab-x,ate (the list shown here ). Is there a way to omit the commas? Or a way to insert the commas automatically – user69453 Jun 19 '14 at 10:24
  • @user69453 I've added another option to the answer as per your request. – Chris Down Jun 19 '14 at 10:31

A note about brace expansion vs globbing.

Brace expansion is not globbing (though the distinction is not as clear in csh/tcsh where it originated as in other shells). It is performed before globbing.

So, when you do:

cp {a,b}* /dest

It is first expanded to:

cp a* b* /dest

That means that the shell will have to expand two globs, that is get the full list of files twice and see which match the pattern twice.

With zsh, that also means that if any of the glob doesn't match any file, the whole command is cancelled (which you can work around by enabling the cshnullglob option to behave like in csh).

That also means that if you have

cp {a,ab}* /dest

cp will copy the ab* files twice.

That's different from the:

cp @(a|b)* /dest

of ksh or bash -O extglob or zsh -o kshglob, or

cp (a|b)* /dest

of zsh. There, it's only one glob, so it will be more efficient, and files will only be included once.

With zsh, if you've got the list of prefixes in an array:

prefixes=(abc abd aer ab-x ate)
cp -- (${(j:|:)~prefixes})* /dest

(above, the prefixes are treated as globs). That is join the elements of the arrays with | and consider the result as a glob (~).

If the list is big, what you may find is that executing cp fails with an "arg list too long" error. In that case, you can use zsh builtin version of cp which you can by loading the zsh/files module (zmodload zsh/files).

| improve this answer | |

Simply you can do

 cp abc* abd* aer* ab-x* ate*  DestinationPath

A solution to your extended problem can be

  1. put all the filenames in a list e.g. list0.txt
  2. Copy all with

    cp `cat list0.txt` DestinationPath # Needs no whitespace in the filenames

    or, better,

    while read -r file; do cp "$file" dest/ ; done < list0.txt


  • "$file" because so you can handle name with white space inside as One Package.deb
  • -r it protect you from escape sequences.

    -r Backslash does not act as an escape character. The backslash is considered to be part of the line. In particular, a backslash- newline pair may not be used as a line continuation

| improve this answer | |
  • This will not work; pathname expansion is not performed when encountering globs in weak quoting. – Chris Down Jun 19 '14 at 10:25
  • @ChrisDown Thx I was too fast too :) – Hastur Jun 19 '14 at 11:17
  • Your list approach will fail on filenames with whitespace. You should use while read file; do cp "$file" dest/ ; done < list0.txt instead. – terdon Jun 19 '14 at 11:40
  • Right, even safer read -r. BTW this example was related to a list of package names of ubuntu with no whitespace inside.@terdon Thx for the spot. – Hastur Jun 19 '14 at 12:00
  • You need IFS= read -r for the leading and trailing blank characters not to be removed. Also note that the newline character is as valid as any in a filename. – Stéphane Chazelas Jun 19 '14 at 12:13

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.