3

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?

user69453
  • 275

4 Answers4

4

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/
done

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):

files=()
includes=(abc abd aer ab-x ate)

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

cp -- "${files[@]}" dest/        
Chris Down
  • 125,559
  • 25
  • 270
  • 266
3

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).

2
  1. For example I have these files in current directory:

    1-s2.0-S0038092X0000058X-main.pdf  ANNDHW.pdf     HPcalculation2
    1-s2.0-S0306261999000422-main.pdf  ANNlee.pdf     HPcalculation3
    ANNCanada.pdf                      HPcalculation  HPcalculation4
    
  2. I want to move all the files starting from HP to folder: ./NewFolder/

  3. I can do:

    cp ./HP* ./NewFolder/
    

    ./HP* will tell linux that I am interested in all the files starting from HP. The reverse is when I am interested in moving all the files ending with .pdf. I can put * in front of the .pdf:

    cp ./*.pdf ./NewFolder/
    
AdminBee
  • 22,803
yogender
  • 121
0

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

Notes:

  • "$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

Hastur
  • 2,355
  • 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