0

I need some text search-replace with minimal tools during linux startup. Sed does not work, probably it finds some special characters in my strings. Is there a solution to turn off this fancy regexp magic and do simple literal search-replace of all plain text occurrences in file? One example which I cannot get to work:

sed -i 's|<![CDATA[http://example.com/file.json]]>|mysvc://{source}|g' my-file.xml

I have about 10 of other different text fragments, these can be long XML, jsons or other with all kind of special chars inside. It would be nice if the command would be maintainable (readable) also.

JaakL
  • 4,107
  • 5
  • 24
  • 37
  • 3
    The magical character is `[`, making sed think you're trying to replace a bracket expression. You have to escape the `[]` if you want them literally. – Benjamin W. Apr 12 '17 at 17:15
  • Or possibly [How to replace paired square brackets with other syntax with sed?](http://stackoverflow.com/q/10646418/3266847) – Benjamin W. Apr 12 '17 at 17:19
  • @BenjaminW. comment was most useful - escaping [ and ] with \ was in practise enough for my small set of strings. – JaakL Apr 12 '17 at 20:26
  • For the people who closed this as a dup - escaping square brackets is NOT the OPs only problem, he has to escape all regexp metacharacters in the search part and all backreference characters in the replacement part. If it was going to be closed as a dup it'd be of http://stackoverflow.com/questions/29613304/is-it-possible-to-escape-regex-metacharacters-reliably-with-sed/29626460#29626460 but in reality he should just be using awk instead. – Ed Morton Apr 12 '17 at 21:00

1 Answers1

1

sed ONLY understands regexps, it does not understand strings. To try to force sed to treat regexps like strings is painful (see Is it possible to escape regex metacharacters reliably with sed) and usually not worth bothering with when you can instead just use awk which DOES understand strings. e.g.:

awk '
BEGIN {
    old = "<![CDATA[http://example.com/file.json]]>"
    new = "mysvc://{source}"
}
s=index($0,old) { $0 = substr($0,1,s-1) new substr($0,s+length(old)) }
{ print }
' my-file.xml

The above is, obviously, untested since you didn't provide any testable sample input/output.

If you need "inplace" editing then if you have GNU awk use awk -i inplace ... and with other awks just use a tmp file: awk '...' my-file.xml > tmp && mv tmp my-file.xml.

Community
  • 1
  • 1
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
  • it probably works also, but it looks less readable than the thing what eventually worked for me: `sed -i 's|<!\[CDATA\[http://example.com/file.json\]\]>|mysvc://{source}|g' my-file.xml` and no other chars in my set needed fixing. I can stack these commands and result seems to be quite readable as script. – JaakL Apr 12 '17 at 20:30
  • You are wrong, that sed command is not doing what you think it's doing and following that approach **WILL** come back to bite you later if not immediately (hint you have other regexp metacharacters in your "string" that you haven't escaped yet and so could cause false matches). I'm also amazed to hear you say the awk command looks less readable than that mush of characters in sed but I suppose it's in the eye of the beholder. – Ed Morton Apr 12 '17 at 20:38
  • If you like replacement syntax, you'll like the perl answers [here](https://superuser.com/questions/422459/substitution-in-text-file-without-regular-expressions) – stevesliva Apr 13 '17 at 17:17