Rahul
Rahul

Reputation: 78

Replace parameter value using sed or awk

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

Answers (5)

Rob H
Rob H

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

M Oehm
M Oehm

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

hek2mgl
hek2mgl

Reputation: 157947

Simple sed solution:

val="2km"
sed "/^[[:blank:]]*A_place[[:blank:]]*=/s/=.*/= ${val}/" file

Upvotes: 0

Henk Langeveld
Henk Langeveld

Reputation: 8446

A generic solution can be done with awk when we assume a couple of things:

  1. Whitespace around = can always be removed
  2. We will search for an exact match on the left hand side
  3. Key values consist of a single unquoted word

With 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

RavinderSingh13
RavinderSingh13

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

Related Questions