user3723380
user3723380

Reputation: 55

Bash: How to add a prefix to a line when a specific number is matched on a line

I have a simple problem which I can't seem to find a proper solution for. I have a line with many lines like this:

2020-10-07;2020-07-17;954;7004;something;something
2020-10-14;2020-07-16;955;10038;something;something

I want to add a prefix 1; to all lines where the 3rd field is matching 954, so it ends up like this:

1;2020-10-07;2020-07-17;954;7004;something;something
2020-10-14;2020-07-16;955;10038;something;something

I have a really bad way of doing this right now with:

cat test.csv | awk -F ';' '{print $1,$2,$3,$4,$5,$6}' | awk '{if($3 == 954) print "1;"$0;}'

But, of course, that outputs with spaces as delimiter.

I would really appreciate it if someone has a smarter way of doing this. Thank you!

Upvotes: 1

Views: 558

Answers (3)

Akshay Hegde
Akshay Hegde

Reputation: 16997

Awk can do your job easily

awk 'BEGIN{FS=OFS=";"}$3 == 954{print 1,$0;next}1' file

#OR

awk 'BEGIN{FS=OFS=";"}$3 == 954{$0=1 OFS $0}1' file

#OR

awk 'BEGIN{FS=OFS=";"}{print ($3==954 ? 1 OFS:"") $0}' file

With your input files:

$ cat file
2020-10-07;2020-07-17;954;7004;something;something 
2020-10-14;2020-07-16;955;10038;something;something

$ awk 'BEGIN{FS=OFS=";"}$3 == 954{print 1,$0;next}1' file
1;2020-10-07;2020-07-17;954;7004;something;something 
2020-10-14;2020-07-16;955;10038;something;something

$ awk 'BEGIN{FS=OFS=";"}$3 == 954{$0=1 OFS $0}1' file
1;2020-10-07;2020-07-17;954;7004;something;something 
2020-10-14;2020-07-16;955;10038;something;something

$ awk 'BEGIN{FS=OFS=";"}{print ($3==954 ? 1 OFS:"") $0}' file
1;2020-10-07;2020-07-17;954;7004;something;something 
2020-10-14;2020-07-16;955;10038;something;something

Explanation

awk 'BEGIN{
         FS=OFS=";"       # set input and output field separator
     }
     $3 == 954{           # if 3rd field equal to 954 then
         print 1,$0;      # print 1 and then existing record/row
         next             # go to next line
     }1                   
     ' 
  • $3 == 954{$0=1 OFS $0}1 : if 3rd field equal to 954, modify existing record/row ($0), with value 1, output field separator OFS and then existing row/record ($0).

  • So at the end }1 : The 1 at the end of your script is a condition (always true) with no action, so it executes the default action for every line, printing the line (which may have been modified by the previous action in braces)

Upvotes: 4

Jetchisel
Jetchisel

Reputation: 7801

With sed, macthing the 3rd column should be fine but if it is more than say 5 columns, then awk is the way.

sed '/\([^;]*\)\([^;]*\);954[^;]*\(.*\)/s/^/1;/' file.txt 

Upvotes: 0

Kent
Kent

Reputation: 195179

This one-liner may help too:

awk -F';' '{p=$3==954?"1;":""}{print p$0}' file 

The reason why you lost the ; int the output:

If you write print $1,$2... awk will use the default OFS which is a space. To solve the problem you have basically two ways to go:

  1. set OFS it is straightforward, as the other answer shows
  2. don't set any field, e.g. don't do something like $2=..., instead, using sub(), gsub() to change the text. When you print, don't include comma ,, just print $0 concatenating other strings. (my one-liners shows this way)

Upvotes: 0

Related Questions