How to copy multiple files from another directory using cp, variables and brackets?

My question is very similar to How to copy multiple files from another directory using cp?

I do not want to use an explicit loop. That's what I'm doing:

$ FILES_TOOLS="fastboot,fastboot-HW.sh" $ cp $HOME/tools/{$FILES_TOOLS} $TOP_DIR/removeme cp: cannot stat `/home/johndoe/tools/{fastboot,fastboot-HW.sh}': No such file or directory 

Files are present and the destination is valid because:

 $ cp $HOME/tools/{fastboot,fastboot-HW.sh} $TOP_DIR/removeme $ echo $? 0 
  • I tried removing the double quote from FILES_TOOLS, no luck.
  • I tried to quote and add a quote twice {...}, no luck
  • I tried dropping the brackets, no luck
  • I assume this is a problem when shell expansion actually occurs.
+4
source share
3 answers

This answer is limited to bash.

Prepare echo to see what your cp command is turning into:

 echo cp $HOME/tools/{$FILES_TOOLS} $TOP_DIR/removeme 

You need to insert eval inside the sub-shell for it to work:

 cp $( eval echo $HOME/tools/{$FILES_TOOLS} ) $TOP_DIR/removeme 
+2
source

I guess this is the problem of when the shell expansion actually occurs.

Yes. Different shells have different rules about expanding brackets with respect to variable expansion. Your method works in ksh, but not in zsh or bash. {1..$n} works in ksh and zsh, but not in bash. In bash, variable expansion always occurs after a chart expansion.

The closest thing you get to this is in bash using eval .

+1
source

As long as the contents of the braces is a literal, you can use the brace extension to populate the array with the full path names for the copied files, and then expand the contents of the array in your cp command.

 $ FILES_TOOLS=( $HOME/tools/{fastboot,fastboot-HW.sh} ) $ cp "${FILES_TOOLS[@]}" $TOP_DIR/removeme 

Update: I realized that you might have a reason for the base names in the variable. Here's another array-based solution that allows you to prefix each element of the array with a path, again without an explicit loop:

 $ FILES_TOOLS=( fastboot fastboot-HW.sh ) $ cp "${FILES_TOOLS[@]/#/$HOME/tools/}" $TOP_DIR/removeme 

In this case, you use the pattern substitution operator to replace the empty string at the beginning of each element of the array with the directory name.

+1
source

All Articles