new born
new born

Reputation: 31

Update a csv file using bash

I have a csv file, with student name and marks. I want to update "marks" of a student with name "jack"(the only person in the csv). the data in csv file looks as below.

student,marks
jack,10
peter,20
rick,10

I found this awk '$1 == "Audrey" {print $2}' numbers.txt, but iam not sure on how to modify the file.

Upvotes: 1

Views: 4059

Answers (5)

David C. Rankin
David C. Rankin

Reputation: 84642

Another approach with sed is to anchor the replacement to the digits at the end of the line with:

sed '/^jack,/s/[0-9][0-9]*$/12/' file

This uses the form sed '/find/s/match/replace' where find locates at the beginning of the line '^' the word "jack," eliminating all ambiguity with, e.g. jackson,33. Then the normal substitution form of 's/match/replace/' where match locates at least one digit at the end of the line (anchored by '$') and replaces it with the 12 (or whatever you choose).

Example Use/Output

With your example file in file, you would have:

$ sed '/^jack,/s/[0-9][0-9]*$/12/' file
student,marks
jack,12
peter,20
rick,10

(note: the POSIX character class of [[:digit:]] is equivalent to [0-9] which is another alternative)

The equivalent expression using the POSIX character class would be:

sed '/^jack,/s/[[:digit:]][[:digit:]]*$/12/' file

You can also use Extended Regular Expression which provides the '+' repetition operator to indicate one-or-more compared to the basic repetition designator of '*' to indicate zero-or-more. The equivalent ERE would be sed -E '/^jack,/s/[0-9]+$/12/' file

You can add the -i option to edit in-place and/or using it as -i.bak to create a backup of the original with the .bak extension before modifying the original.

Upvotes: 0

Ed Morton
Ed Morton

Reputation: 204638

awk 'BEGIN{FS=OFS=","} $1=="jack"{$2=27} 1' foo.csv > tmp && mv tmp foo.csv

Upvotes: 3

Shawn
Shawn

Reputation: 52644

ed is usually better for in-place editing of files than sed:

printf "%s\n" "/^jack,/c" "jack,${new_grade}" "." w | ed -s input.csv

or using a heredoc to make it easier to read:

ed -s input.csv <<EOF
/^jack,/c
jack,${new_grade}
.
w
EOF

At the first line starting with jack,, change it to jack,XX where XX is the value of the new_grade variable, and write the new contents of the file.

Upvotes: 1

new born
new born

Reputation: 31

It worked for me with

sed -ir "s/^\(jack\),.*/\1,$new_grade/" 

input.csv. with argument "r" or else i get the "error sed: 1: "input.csv": command i expects \ followed by text".

Upvotes: 1

builder-7000
builder-7000

Reputation: 7657

You could use sed:

new_grade=9
sed -i'' "s/^\(jack\),.*/\1,$new_grade/"

The pattern ^\(jack\),.* matches the beginning of the line ^ followed by jack by a comma and the rest of the line .*. The replacement string \1,$new_mark contains the first captured group \1 (in this case jack) followed by a comma and the new mark.

Alternatively you could loop over the file and use a pattern substitution:

new_grade=9
while read -s line; do
    echo ${line/jack,*/jack,$new_grade}
done < grades.txt > grades2.txt

Upvotes: 0

Related Questions