Search code examples
sedreplacegrepspecial-characters

Find and replace words and special characters from specific files from linux


I have some multiple gnuplot files, and I wish to find and replace "set xrange [0:20]" to "set xrange [0:3]" for series of files of "gnuplot_RTre_*.gnplt" in current directory. I found how to swap specific strings from all files from folder, but not only for specific files including special characters.

So I tried

find . -type f -name "gnuplot_RTre_*.gnplt" -exec sed -i 's/set xrange [0:20]/set xrange [0:3]/g' {} +

It doesn't make an error, but it swaps nothing from those files. So I tried to escape special characters using backslash

find . -type f -name "gnuplot_RTre_*.gnplt" -exec sed -i 's/set xrange \\[\\0\\:\\20\\]\\/set xrange \\[\\0\\:\\3\\]\\/g' {} + 

Still not working, no error, but no swapping.

I also tried

grep -rl 'set xrange [0:20]' ./ | xargs sed -i 's/set xrange [0:20]/set xrange [0:3]/g' gnuplot_RTre_*.gnplt

But it is not working as well.

I think my commands are wrong with special character escaping or file selection, but not sure how to solve this issue. Need some helps.

Thank you


Solution

  • You have extra backslashes to escape special characters. Please try:

    # find . -type f -name "gnuplot_RTre_*.gnplt" -exec sed -i 's/set xrange \[0:20]/set xrange \[0:3]/g' {} +
    # The backslash in the REPLACEMENT above is unnecessary, although harmless.
    # Please adopt the following instead.
    find . -type f -name "gnuplot_RTre_*.gnplt" -exec sed -i 's/set xrange \[0:20]/set xrange [0:3]/g' {} +
    

    In sed, the characters $.*[\^ need to be escaped with a backslash to be treated as literal.

    [EDIT]
    The right square bracket "]" is usually not a special character in regex and you do not have to esacape it:

    echo "[abc]" | sed 's/]/*/g'
    => [abc*
    

    But "]" behaves as a metacharacter if preceded by an unescaped left square bracket "[" to compose a character class.

    echo "[abc]abc" | sed 's/[abc]/*/g'
    => [***]***
    

    In order to make "[" to be literal, we need to escape it.

    echo "[abc]abc" | sed 's/\[abc]/*/g'
    => *abc
    

    "]" can be also escaped just for visual symmetricity.

    echo "[abc]abc" | sed 's/\[abc\]/*/g'
    => *abc