Reputation: 78
I have some configuration file like example
A_place = 10km
B_place=5km
#A_place=2km
C_place=1km
I want to change the A_place value in the uncommented line. Some of the lines may have initial spaces. I tried a basic sed
command to find and replace it but it didn't work. Perhaps I should use AWK
rather than stream editor?
Upvotes: 2
Views: 7163
Reputation: 1716
using sed:
sed -e '/#/!s/\(A_place[[:space:]]*=[[:space:]]*\)\(.*\)/\1"new_value"/' input
breakdown of what is being done here:
skip lines that are comments:
/#/!
Then comes the substitution in the form
s/old/new/
Select the old, and put the original string inside parens (backreferencing) so that it can be retained later by specifying \1. This matches the string "A_place" followed by zero or more whitespace chars followed by the equal sign followed by zero more more whitespaces chars. Note that the value to be replaced is also in parens and could be referenced by \2; it is not needed here and the parens can be left off. So the old string to match is:
( A_place[[:space:]]*=[[:space:]]* ) (.*)
Then the new line to output is created using the "\1" backref, preserving the whitespace around the equals sign and appending the "new value", shown here with quotation marks for clarity which are a literal in the new line but probably not wanted in the final output. "\1" here is everything that was matched in the first paren delimited regex, including any whitespace around the equals sign:
\1"new_value"
Upvotes: 5
Reputation: 29116
The following sed expression will set the new distance of A_place
to 32km. The spaces of everything up to the new distance are retained:
> cat kk.config
A_place = 10km
B_place=5km
#A_place=2km
C_place=1km
> sed -i -e 's/^\( *A_place *= *\).*/\132km/' kk.config
> cat kk.config
A_place = 32km
B_place=5km
#A_place=2km
C_place=1km
One of the problems with regular expressions is that there are so many flavours. Apparently, sed uses basic regexes and you have to backslash the parentheses if you want to group stuff for later back references. The caret will start matching from the beginning of the line and therefore ignore the match in comments.
Upvotes: 1
Reputation: 157947
Simple sed
solution:
val="2km"
sed "/^[[:blank:]]*A_place[[:blank:]]*=/s/=.*/= ${val}/" file
Upvotes: 0
Reputation: 8446
A generic solution can be done with awk
when we assume a couple of things:
=
can always be removedWith this we can create a small shell wrapper run.sh
with the key and value as parameters:
key=$1
value=$2
awk -F '[ =]*' \
-v key=$key \
-v value=$value \
'/^#/ { print; next }
$1 == key { $2 = value }
{ print $1 "=" $2 }' sample.txt
Example run:
$ sh run.sh A_place 20km
A_place=20km
B_place=5km
#A_place=2km
C_place=1km
Upvotes: 0
Reputation: 133428
Following awk
may help you in same.
awk '!/#/{sub(/A_place/,"new_value")} 1' Input_file
OR in case OP wants to change the A_place
string's last column value then use:
awk '!/#/ && /A_place/{$NF="new_value"} 1' Input_file
In case you have more than 1 occurrences of string A_place
then change sub
to gsub
. Also if you want to save output into same Input_file then you could use following code too for same then.
awk '!/#/{sub(/A_place/,"new_value")} 1' Input_file > temp_file && mv temp_file Input_file
OR
awk '!/#/ && /A_place/{$NF="new_value"} 1' Input_file > temp_file && mv temp_file Input_file
Upvotes: 1