Dr. Debasish Jana Dr. Debasish Jana - 1 month ago 14
Bash Question

gawk and grep using same pattern but need different treatement for escape sequence

I have a bash shell script (named

testawk
to replace a line containing a pattern (1st arg) with one or more than one line (2nd arg) and operates on the filename given in 3rd arg. The shell script is given below:

#!/bin/bash
if grep -s "$1" "$3" > /dev/null; then
gawk -v nm2="$2" -v nm1="$1" '{ if ($0 ~ nm1) print nm2;else print $0}' "$3" > "$3".bak
mv "$3".bak "$3"
fi


If I have a file named "aa" containing the following:

a;
b<*c;


And, if I run
testawk
as:

./testawk "a;" "x<*y;" "aa"


aa contains:

x<*y;
b<*c;


But, if I run
testawk
on original
aa
file again as:

./testawk "b<*c;" "x<*y;" "aa"


aa
contains now as (unchanged content):

a;
b<*c;


Because,
grep "b<*c;" "aa"
cannot find the pattern.
To make
grep
happy, if I use escape sequences as:

grep "b<\*c;" "aa"


It could match and shows:

b<*c;


if I use testawk using the escape sequence as below:

./testawk "b<\*c;" "x<*y;" "aa"


gawk
does not like that and complains as:

gawk: warning: escape sequence `\*' treated as plain `*'


And
aa
gets no changed content as:

a;
b<*c;


Any remedy to make both
grep
and
gawk
happy to find and replace
b<*c;

Please suggest how to replace
b<*c;
.

Answer

This should do what I think you are asking for:

if awk -v nm2="$2" -v nm1="$1" 'index($0,nm1){f=1; $0=nm2} 1; END{exit !f}' "$3" > "${3}.bak"
then
    mv "${3}.bak" "$3"
    # do stuff with modified file "$3"
else
    rm -f "${3}.bak"
    # do stuff with unmodified file "$3"
fi

No need to escape anything except backslashes and we can deal with that differently if you have those.