2

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.

Rui F Ribeiro
  • 55,929
  • 26
  • 146
  • 227
RoboHay
  • 23
  • 3

2 Answers2

2

It should be:

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

EDIT:

You can reproduce it with this example:

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

$ echo ${i}_7
1_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.

And:

   ${parameter}
          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 _.

Arkadiusz Drabczyk
  • 25,049
  • 5
  • 53
  • 68
0

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"

or

while IFS= read -r i; do
    cp binaryfile.docx "${i}_binaryfile.docx"
done < file
pLumo
  • 22,231
  • 2
  • 41
  • 66
  • 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