0

So I have a this below line in a file which has special characters & I want to replace it with another line.

Line present in file -

'generic_raid': {'keys': 5 * (1000**3)

Line with which I want to replace the above line-

'generic_raid': {'keys': 2

I am using the below sed command but it is not working, can anyone please help

sudo sed -r -i "s/'generic_raid': \{'keys': 5 * (1000**3)/'generic_raid': \{'keys': 2/g" abc.py
zvone
  • 18,045
  • 3
  • 49
  • 77
DD1
  • 357
  • 4
  • 14
  • 3
    escape curly braces, *, (, ) – Avinash Raj Sep 27 '16 at 15:05
  • Thanks a lot Avinash, it worked. I used the below command - sudo sed -r -i "s/'generic_raid': \{'keys': 5 \* \(1000\*\*3\)/'generic_raid': \{'keys': 2/g" abc.py – DD1 Sep 27 '16 at 15:12
  • 1
    And in a pinch, if you're not sure whether you need to escape something, you can put a character into square brackets. `[*]` matches `*`, `[{]` matches `{`, etc. – ghoti Sep 27 '16 at 15:12
  • 1
    To expand on Avinash's comment, [this regexr](http://regexr.com/3eaki) is your search pattern - red underlines are errors. – cxw Sep 27 '16 at 15:13
  • Thanks ghoti & cxw for the suggestions, appreciate your suggestions. – DD1 Sep 27 '16 at 15:15

2 Answers2

0

can simplify by avoiding use of extended regex, only * needs to be escaped in this case

$ cat ip.txt 
'generic_raid': {'keys': 5 * (1000**3)
$ sed "s/'generic_raid': {'keys': 5 \* (1000\*\*3)/'generic_raid': {'keys': 2/g" ip.txt 
'generic_raid': {'keys': 2

not required in this case, but if " is undesirable and ' features in pattern, ascii code \x27 can be used

$ sed 's/\x27generic_raid\x27: {\x27keys\x27: 5 \* (1000\*\*3)/\x27generic_raid\x27: {\x27keys\x27: 2/g' ip.txt 
'generic_raid': {'keys': 2

Also, a perl solution which has a \Q feature helpful in these cases:

$ perl -pe "s/\Q'generic_raid': {'keys': 5 * (1000**3)/'generic_raid': {'keys': 2/" ip.txt 
'generic_raid': {'keys': 2

From perldoc

Returns the value of EXPR with all the ASCII non-"word" characters backslashed. (That is, all ASCII characters not matching /[A-Za-z_0-9]/ will be preceded by a backslash in the returned string, regardless of any locale settings.)

Sundeep
  • 23,246
  • 2
  • 28
  • 103
  • Always use octal `\047`, never hex `\x27` to represent a single quote. See http://awk.freeshell.org/PrintASingleQuote. YMMV with either in sed of course. – Ed Morton Sep 27 '16 at 15:58
  • @EdMorton does it affect `sed`? didn't affect for me on `GNU sed 4.2.2` – Sundeep Sep 27 '16 at 16:03
  • Y'know I'm not sure. I assumed so but I always use `'\''` with sed so idk. – Ed Morton Sep 27 '16 at 16:07
  • didn't see your edit before I left the comment, searched around a bit and see that `\x27` is commonly used, for ex: http://stackoverflow.com/questions/24509214/how-to-escape-single-quote-in-sed ... thanks for warning though, will remember for `awk` or elsewhere if something is fishy :) – Sundeep Sep 27 '16 at 16:08
  • 1
    You're welcome. Unfortunately on this site and others you'll find lots of examples endorsing the use of everything you should never actually do since they often produce the expected output for a given sample input and only fail later given different input. In this case, I'd personally avoid `\x27` anyway and use `'\''` if `\047` doesn't work for you since `\x27`s been proven to be problematic in other text processing tools/situations but YMMV I suppose. – Ed Morton Sep 27 '16 at 16:12
0

Since sed doesn't have any string operations, it takes a lot of work to force a sed expression to behave as if it were working with strings (see Is it possible to escape regex metacharacters reliably with sed) so just don't. Instead use awk since it supports string operations:

awk -v old="'generic_raid': {'keys': 5 * (1000**3)" \
    -v new="'generic_raid': {'keys': 2" \
       's=index($0,old){$0=substr($0,1,s-1) new substr($0,s+length(old))} 1' file
'generic_raid': {'keys': 2
Community
  • 1
  • 1
Ed Morton
  • 188,023
  • 17
  • 78
  • 185