0

I have a following code

sed -i '' $line'i\
${String}\
' test.csv

where line=3 and string='"a","b","c"'.

But it doesn't work as expected. It adds the string on each alternate line. It is supposed to add the string on 3rd line. Same command works fine if I use the variable values directly in command.

Edit: This command should work on MacOSX. (The -i '' notation is necessary to overwrite the file on MacOSX.)

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Vicky
  • 801
  • 7
  • 7
  • 1
    Use double quotes and the curly braces around `line`: `sed -i "${line}i\ ..." test.csv` – lurker Apr 06 '18 at 10:52
  • Possible duplicate of [Environment variable substitution in sed](https://stackoverflow.com/questions/584894/environment-variable-substitution-in-sed) – agc Apr 06 '18 at 23:13

2 Answers2

1

In general, put the shell variables in double quotes, and keep the rest of the sed code in single quotes:

sed -i '' "${line}"'i\
'"${String}"'\
' test.csv
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
agc
  • 7,973
  • 2
  • 29
  • 50
1

Variables are only expanded when unquoted (not recommended) or when enclosed in double quotes; they are not expanded inside single quotes.

When there are but one or two backslashes to be escaped, it is not unreasonable to put the entire string inside double quotes, doubling up the backslashes. If you have any back-quotes, you need to escape those too. If you have more than a couple of backslashes or you have back-quotes, using single quotes generally becomes your better bet.

Given a data file test.csv containing:

bizarre,multiple,words
plain,simple,words
catastrophic,failure,of,imagination
pejorative,interjections,ignored
abelone,abyssinia,ablation
pokemon,harry,potter

Thus, you can achieve the effect you want with:

$ line=3
$ string='"a","b","c"'
$ sed "${line}i\\
> ${string}
> " test.csv
bizarre,multiple,words
plain,simple,words
"a","b","c"
catastrophic,failure,of,imagination
pejorative,interjections,ignored
abelone,abyssinia,ablation
pokemon,harry,potter
$

The newline after ${string} is required. Curiously, you can also add one or two backslashes after ${string} and get the same result. Or you can quote selected parts of the command in single quotes, making sure that variables are not in single quotes but are in double quotes:

$ sed "${line}"'i\
> '"$string"'
> ' test.csv
bizarre,multiple,words
plain,simple,words
"a","b","c"
catastrophic,failure,of,imagination
pejorative,interjections,ignored
abelone,abyssinia,ablation
pokemon,harry,potter
$

I've not used the -i '' options to overwrite the file (creating a 'backup' without any extension) so that the output is seen on standard output — the terminal. You can add those options on macOS to overwrite the file. The corresponding notation on Linux (GNU sed) is just the -i option. You can use -i.bak on both platforms to create a backup with the extension .bak; on Linux, you cannot have a space between the -i and the .bak, but the space is allowed on macOS. Thus -i.bak is the only portable notation, and it creates the backup — and the portability is still limited as other Unix variants may not support the -i option at all.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278