Reputation: 148
I want to replace a line in a file using bash tools like sed or awk. The part that makes this hard is that the line is not unique, so how can I match it?
I'm sure getting the match by itself could be done other ways, but I only know the following command for replacing lines:
sed -i "s,^ AGE: .*, AGE: ${age}," profiles.txt
The profiles.txt looks like:
ALICE:
AGE:
GRADE:
BOB:
GRADE:
AGE:
...
How can I find the AGE:
line for a specific person and update it? The fields for each person can be in any order, and so can the people. The people will always have both fields, they're just blank if unknown.
Upvotes: 0
Views: 134
Reputation: 15313
A simplistic sed
script:
#! /bin/bash
declare -u student=$1
declare -u key=$2
declare val=$3
sed -Ei "/^$student:/,/^\S/{ s/$key:.*/$key: $val/; }" profiles.txt
Executed:
$: cat profiles.txt
ALICE:
AGE:
GRADE:
BOB:
GRADE:
AGE:
$: update alice grade 70
$: cat profiles.txt
ALICE:
AGE:
GRADE: 70
BOB:
GRADE:
AGE:
declare -u
automatically uppercases the string assigned to the variable. This was a pretty simple pattern set, so I was able to just use double-quotes.
this works fine on the last block:
$: update bob age 14
$: cat profiles.txt
ALICE:
AGE:
GRADE: 70
BOB:
GRADE:
AGE: 14
The toggle is still on at the end of the file because nothing turns it off, but that is functionally ok. :)
Upvotes: 1
Reputation: 785286
You may use this awk
(assuming you want to change AGE
for person BOB
):
awk -v age=20 -v name='BOB' '/^[[:alpha:]]+:/ {
p = ($0 ~ "^" name ":")
}
p && /^[[:blank:]]+AGE:/ {
sub(/AGE:.*/, "AGE: " age)
} 1' file.yml
ALICE:
AGE:
GRADE:
BOB:
GRADE:
AGE: 20
Upvotes: 4
Reputation: 41454
You can do it like this in awk
to set the age for BOB
age=10
awk -v val=${age} '/BOB/ {f=1} f && /AGE/ {$0=$0 FS val;f=0} 1' file
ALICE:
AGE:
GRADE:
BOB:
GRADE:
AGE: 10
...
It will find BOB
and set f
to true. The if f
is true and AGE
is found, add age and reset f
Upvotes: 4