4

I am trying to write a sed command to replace a line in a file. The sed replace required the current working directory, which starts making the command a bit messy because of the characters that need to be escaped.

Here is what I have so far:

sed -i "s/^log.*$/log `echo pwd | sed 's/\//\\\//g'`\/redis\/redis.log\/" ./conf/redis.conf

However this give me an error with sed.

I have tried to break it up into easier commands:

user@ubuntu:~/project$pwd | sed 's/\//\\\//g'
\/home\/user\/project

This returns what I want, but when I try to add in command substitution, it fails:

user@ubuntu:~/project$ echo `pwd | sed 's/\//\\\//g'`
sed: -e expression #1, char 9: unknown option to `s'

Any help would be appreciated

7

If I'm reading that right, you're trying to replace forward slashes (/) with an escaped forward slash (\/)? This gets a lot easier to handle if you don't use / as your delimiter in sed:

~ $ pwd | sed 's_/_\\/_g'`
\/home\/username
~ $ echo "$( pwd | sed 's_/_\\/_g' )"
\/home\/username
  • 2nd command fixed it. When i was using `` instead of $() bash was removing the backslashes – Franz Payer Jan 16 '14 at 18:55
  • That's one of many reasons that `` subshells have been deprecated in favor of $() subshells- they're much better-behaved with nesting in many ways. Learning about using other sed delimiters also removed a lot of non-human-parseable 'picket fences' in some of my scripts. Glad to have helped! – DopeGhoti Jan 16 '14 at 18:57
2

You're setting yourself up for some complication here, since backslashes are interpreted

  1. by the shell inside the command substitution,
  2. by the shell outside the command substitution,
  3. by sed.

First, don't use the backtick form of command substitution: its rules for quotes inside are intrincate. Use dollar-parentheses, which has intuitive rules — what's inside is parsed normally, with the matching close parenthesis marking the end of the subshell.

Then you're using double quotes for a sed command. Avoid this: your sed command can't be written literally, you need to protect \ and $ both for the shell and for sed. Use single quotes instead.

Also you have slashes inside your replacement text. Sed can't know that these slashes aren't part of its syntax but literal text that you want to include. You can use a character other than / to delimit an s, g or m command. Use a character that never appears in your replacement text (fortunately, here, it's easy because you know the replacement text).

I presume that echo pwd should really be pwd (or echo "$PWD"). Without the need to protect the slashes, you don't need the nested sed call. If you did need to transform pwd, consider using $PWD and the shelll's string manipulation facilities instead.

sed -i 's~^log.*$!log '"$PWD"'/redis/redis.log!' ./conf/redis.conf

If you have a hard time with the quoting, don't hesitate to use an easier tool such as Perl. Perl combines the features of sed and of the shell, so you don't run into quoting issues between the two.

perl -MCwd -i -pe 'BEGIN {$PWD = cwd} s[^log.*][log $PWD/redis/redis.log]' conf/redis.conf

or

perl -MCwd -i -pe '$_ = cwd."/redis/redis.log" if /^log' conf/redis.conf

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.