I am finding a bash command for a conditional replacement with offset. The existing posts that I’ve found are conditional replacement without offset or with a fixed offset.
Task: If uid
contains 8964
, then insert the line FORBIDDEN
before DOB
.
Each TXT file below represents one user, and it contains (in the following order)
- some property(ies)
- unique
uid
- some quality(ies)
- unique
DOB
- a random lorem ipsum
I hope I can transform the following files
# file1.txt (uid doens't match 8964)
admin: false
uid: 123456
happy
movie
DOB: 6543-02-10
lorem ipsum
seo varis lireccuni paccem noba sako
# file2.txt (uid matches 8964)
citizen: true
hasSEAcct: true
uid: 289641
joyful hearty
final debug Juno XYus
magazine
DOB: 1234-05-06
saadi torem lopez dupont
into
# file1.txt (uid doens't match 8964)
admin: false
uid: 123456
happy
movie
DOB: 6543-02-10
lorem ipsum
seo varis lireccuni paccem noba sako
# file2.txt (uid matches 8964)
citizen: true
hasSEAcct: true
uid: 289641
joyful hearty
final debug Juno XYus
magazine
FORBIDDEN
DOB: 1234-05-06
saadi torem lopez dupont
My try:
If uid
contains 8964
, then do a 2nd match with DOB
, and insert FORBIDDEN
above DOB
.
sed '/^uid: [0-9]*8964[0-9]*$/{n;/^DOB: .*$/{iFORBIDDEN}}' file*.txt
This gives me an unmatched {
error.
sed: -e expression #1, char 0: unmatched `{'
I know that sed '/PAT/{n;p}'
will execute {n;p}
if PAT
is matched, but it seems impossible to put /PAT2/{iTEXT}
inside /PAT/{ }
.
How can I perform such FORBIDDEN
insertion?
3
Answers
Alternatively, treat every block separated by a blank line as a single record, then sub in “FORBIDDENnDOB” if there’s a match. I think the first one’s better practice. As a very general rule, once you start thinking in terms of fields/records, it’s time for awk/perl.
In my opinion, this is a good use-case for sed.
Here is a GNU sed solution with some explanation:
Testing:
Or on one line:
tried on gnu sed