0

I have a line in my file that I'm trying to replace using sed -i but have been running into problems.

The line is

set feat_files(1) "/Users/lab/Desktop/1026/20170802151230_1"

and I want to change it to

set feat_files(1) "/Users/lab/Desktop/1026/20170802151230_2"

So far I've tried the following with no luck:

line_old="/Users/lab/Desktop/1026/20170802151230_1" line_new="/Users/lab/Desktop/1026/20170802151230_2"

sed -i '' 's/feat_files(1) '$line_old'/feat_files(1) '$line_new'/' $file

djl
  • 267
  • 1
  • 3
  • 13
  • Change single quote into double quote. `sed -i "s|$line_old|$line_new|g" $file` – iamauser Oct 26 '18 at 17:36
  • This is a duplicate — but I don't immediately have the question it's a duplicate of on hand. Searching is required. It's a standard `sed` problem.' – Jonathan Leffler Oct 26 '18 at 17:51
  • See: [Difference between single and double quotes in bash](http://stackoverflow.com/q/6697753/3776858) – Cyrus Oct 26 '18 at 18:38

3 Answers3

0

Is it not enough to?:

sed -i '' 's/20170802151230_1/20170802151230_2/'
Rafael
  • 7,605
  • 13
  • 31
  • 46
  • It depends, but in general, no. For the particular change shown in the question, yes, but the necessary change might not be as conveniently simple as that. – Jonathan Leffler Oct 28 '18 at 18:12
0

Problem is with single quote. Use double quotes when replacing with a shell variable.

$ sed "s|$line_old|$line_new|g" input_file 
set feat_files(1) "/Users/lab/Desktop/1026/20170802151230_2"
iamauser
  • 11,119
  • 5
  • 34
  • 52
  • The problem isn't the single quotes because the question uses `'s/feat_files(1) '$line_old'/feat_files(1) '$line_new'/'` which terminates the single-quoted string before interpolating `$line_old` and `$line_new`. The key change in your answer is the use of `|` instead of `/` for delimiting the sections of the `s///` command. I note that you've eliminated the `feat_files(1)` part of the context so your example could make unwanted changes, in theory. – Jonathan Leffler Oct 28 '18 at 18:09
0

The slashes in the replacement text confuse sed about what's part of the s/// command and what is pathname. The fix is easy — use a different character to mark the parts of the substitute command:

sed "s%feat_files(1) $line_old%feat_files(1) $line_new%" $file

This uses a % in place of the /; you could use any character that doesn't appear in the file names. Consider Control-A or another control character if you think % might appear some time.

You can even change the character marking the ends of a searching (matching) regex if need be:

sed "\\%feat_files(1) $line_old%,\\%feat_files(1) $line_new% { … }"

to match the lines between the patterns in $line_old and $line_new.

I use double quotes because of the variables. An alternative is to do what the question started to do, and use single quotes, but you should still surround the variables in double quotes:

sed 's%feat_files(1) '"$line_old"'%feat_files(1) '"$line_new"'%' $file

The code in the question must be running on a Mac with the BSD sed. The GNU sed variant doesn't like the empty argument after the -i option; you specify just -i with GNU sed to do in-situ replacement. For portability, you need to use -i.bak with a non-empty suffix attached to the -i option — and you have to remove the backup.

Don't use the -i option (with either version of sed) until you've got the basics working. It can wreck your original file if you aren't careful. (Of course, you're probably working on a copy of the original while testing, but having to restore the file to a known state before each test is unnecessary work, in my book. It's much easier just to leave the file unchanged until you know the script will work.)

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