Reputation: 55
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
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
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
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:
OFS
it is straightforward, as the other answer shows$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