I have a list of names and I have a binary file. I want to copy that binary file so that there is one copy for each member of the list. The list is a text file with one name in each row. I keep coming back to

for i in $(cat ../dir/file); do cp binaryfile.docx "$i_binaryfile.docx"; done

There is no error. Only one file titled _binaryfile.docx is created.

I have looked at this [Copy-a-file-to-a-destination-with-different-names] and [duplicate-file-x-times-in-command-shell] but I cannot see how they are different.


It should be:

for i in $(cat file); do cp binaryfile.docx "${i}_binaryfile.docx"; done


You can reproduce it with this example:

$ i=1
$ echo $i
$ echo $i_7

$ echo ${i}_7

The point is that _ (underscore) character is allowed in variable name. You can read about it in man bash but keep in mind that it's written in a very technical, succinct language:

   name   A  word  consisting  only  of alphanumeric characters and underscores, and
          beginning with an alphabetic character or an underscore.  Also referred to
          as an identifier.

And later on:

A variable is a parameter denoted by a name.


          The value of parameter is  substituted.   The  braces  are  required  when
          parameter  is  a  positional  parameter  with more than one digit, or when
          parameter is followed by a character which is not  to  be  interpreted  as
          part  of  its name.  The parameter is a shell parameter as described above
          PARAMETERS) or an array reference (Arrays).

So if we have a variable named i and we want to print its value next to adjacent _ we have to enclose it in {} to tell Bash that the name of the variable ends before _.

  • Can you please explain the answer? – Prvt_Yadav Oct 10 '18 at 15:07
  • @Debian_yadav: I updated my answer. – Arkadiusz Drabczyk Oct 10 '18 at 15:18
  • As noted by RoVo this technique is best being avoided. – don_crissti Oct 10 '18 at 16:10

You have two issues in your command:

The first has already been described by @Arkadiusz Drabczyk answer:

The underscore is a valid character for variable names, so your variable name doesn't stop after $i. You should use ${i}.

The second issue: You should not loop over lines of a file using for line in $(cat file); .... While this might work for you in this case, it is generally very bad practice, as it will split words, not lines.

Better to use something else, e.g.

xargs -a file -I{} cp binaryfile.docx "{}_binaryfile.docx"


while IFS= read -r i; do
    cp binaryfile.docx "${i}_binaryfile.docx"
done < file
  • Avoid processing text with while..read. You can do this easily and safely if you read the filenames into an array then iterate over the elements and run cp source element. – don_crissti Oct 10 '18 at 16:12

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.