I need to search and replace a pattern from file
[ec2_server]
server_host=something
[list_server]
server_host=old_name
to
[ec2_server]
server_host=something
[list_server]
server_host=new_name
I'm able to get it working with
awk '/\[list_server]/ { print; getline; $0 = "server_host=new_name" } 1'
But I'm trying to parameterize the search pattern, the parameter name to change and the parameter value to change.
PATTERN_TO_SEARCH=[list_server]
PARAM_NAME=server_host
PARAM_NEW_VALUE=new_name
But it is not working when I parameterize and pass the variables to awk
awk -v patt=$PATTERN_TO_SEARCH -v parm=$PARAM_NAME -v parmval=$PARAM_NEW_VALUE '/\patt/ { print; getline; $0 = "parm=parmval" } 1' file.txt
CodePudding user response:
You have two instances of the same problem: you're trying to use a variable name inside a string value. Awk can't read your mind: it can't intuit that sometimes when your write "HOME" you mean "print the value of the variable HOME" and other times you mean "print the word HOME".
We need to make two separate changes:
First, to use a variable in your search pattern, you can use syntax like this:
awk -v patt='some text' '$0 == patt {print}'
(Note that here we're using an equality match, ==
; you can also use a regular expression match, ~
, but in this particular case that would only complicate things).
With your example file content, running:
awk -v patt='[list_server]' '$0 == patt {print}' file.txt
Produces:
[list_server]
Next, when you write $0 = "parm=parmval"
, you're setting $0
to the literal string parm=parmval
. If you want to perform variable substitution, consider using sprintf()
:
awk \
-v patt=$PATTERN_TO_SEARCH \
-v parm=$PARAM_NAME \
-v parmval=$PARAM_NEW_VALUE \
'
$0 == patt { print; getline; $0 = sprintf("%s=%s\n", parm, parmval) } 1
' file.txt
Which gives us:
[ec2_server]
server_host=something
[list_server]
server_host=new_server
CodePudding user response:
Have your awk
code in following way, as experts recommend not to use getline
(since it has edge cases in its use). So I am going with find the string and then set flag(custom variable made by me in program) and then print the line accordingly with using regex along with passed value from shell variable.
Along with matching and printing the new value we need to set field separator also to fetch correct value and replace/print it with new value. So I made field separator as =
here for whole Input_file. By doing this approach you need not to pass any variable which has server_host
value in it, since its already present in Input_file so we can take it from there.
awk
solution with mentioning value within awk
variable itself and then check regex in main program of awk
for comparison.
awk -v var="list_server" -v newVal="NEW_VALUE" '
BEGIN{ FS=OFS="=" }
$0 ~ "^\\[" var "\\]$"{
found=1
print
next
}
found{
print $1 OFS newVal
found=""
next
}
1
' Input_file
OR awk
solution to get value from shell variable and then use regex inside awk
to match condition:
varS="list_server" ##Shell variable
newvalue="NEW_VALUE" ##Shell variable
awk -v var="$varS" -v newVal="$newvalue" '
BEGIN{ FS=OFS="=" }
$0 ~ "^\\[" var "\\]$"{
found=1
print
next
}
found{
print $1 OFS newVal
found=""
next
}
1
' Input_file
CodePudding user response:
This makes the assumption "${PARAM_NAME}"
immediately follows the search pattern row :
_P2S_='[list_server]' _PNM_='server_host' _PNV_='new_name' echo "${...input...}" | gtee >( gpaste - | gcat -b >&2; echo ) | gcat - | {m,n,g}awk -v __="${_P2S_}=${_PNM_}=${_PNV_}" -F= 'BEGIN { $(_-=_)=__;___= $(_ = NF); FS ="^"(OFS = $--_ FS) __= $-(_ =-_--) } (NR-_)< NF ? ($NF =___)^(_-=_) :_=NR*(-!!_)^(__!=$!_)' | gcat -b | gcat -n | ecp
1 [ec2_server]
2 server_host=something
3 [list_server]
4 server_host=old_name
1 1 [ec2_server]
2 2 server_host=something
3
4 3 [list_server]
5 4 server_host=new_name