I see nothing wrong with using sed
in this case. It's the right tool for the job.
Your command works well (on the given data):
$ sed '/baz/s/foo/bar/g' food.txt
mangoes|foo|faa
oranges|foo|faa
chocolates|bar|baz
Using a regular expression to match any string beginning with |b
and ending with z
at the end of the line (instead of baz
anywhere on the line):
$ sed '/|b.*z$/s/foo/bar/g' food.txt
mangoes|foo|faa
oranges|foo|faa
chocolates|bar|baz
To make the change to the file (with GNU sed
):
$ sed -i '/|b.*z$/s/foo/bar/g' food.txt
or (with any sed
implementation):
$ sed '/|b.*z$/s/foo/bar/g' food.txt >tmpfile && mv tmpfile food.txt
You could also use awk
:
$ awk 'BEGIN { OFS=FS="|" } $3 == "baz" { $2 = "bar" }; 1' file
mangoes|foo|faa
oranges|foo|faa
chocolates|bar|baz
or matching ^b.*z$
in the 3rd field,
$ awk 'BEGIN { OFS=FS="|" } $3 ~ /^b.*z$/ { $2 = "bar" }; 1' file
mangoes|foo|faa
oranges|foo|faa
chocolates|bar|baz
... or Miller (mlr
), here reading the input as a header-less CSV file that uses |
as field delimiters:
$ mlr --csv -N --fs pipe put '$3 == "baz" { $2 = "bar" }' file
mangoes|foo|faa
oranges|foo|faa
chocolates|bar|baz
or,
$ mlr --csv -N --fs pipe put '$3 =~ "^b.*z$" { $2 = "bar" }' file
mangoes|foo|faa
oranges|foo|faa
chocolates|bar|baz
The benefit of using awk
or Miller is that it's easier and safer to match a pattern against an isolated field. Miller has the added benefit of understanding CSV quoting rules.
b*z
(0 or moreb
followed by az
) orb.*z
(ab
followed by 0 or more characters and then az
)? – terdon Aug 15 '16 at 10:57