I have a tab-delimited file that contains 4 columns
numbers.txt
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
In bash I need to be able to increment a specific column and line by 1, so for example +1 to column 2 line 3 to make it
0 0 0 0
0 0 0 0
0 1 0 0
0 0 0 0
I can get a specific column and line using
cat test | awk '{print $2}' | sed '3!d;q'
which returns 1 as expected but I can’t work out how to update the value in a specific column/line i.e.
cat test | awk '{print $2}' | sed '3!d;q' | +1 to the value in this column
3
This awk
should work for you:
awk -v r=3 -v c=2 'BEGIN {FS=OFS="t"} NR == r {++$c} 1' file
0 0 0 0
0 0 0 0
0 1 0 0
0 0 0 0
1
Here is a Ruby that allows passing multiple values in a JSON array and all the changes are made at once (if they can be, based on the CSV table size):
ruby -r csv -r JSON -e '
opts={:col_sep=>"t", :converters=>:all}
cng=JSON.load(ARGV[0])
tbl=CSV.parse(File.open(ARGV[1]).read, **opts)
cng.each{|(r,c),v| tbl[r][c]+=v if r.abs<tbl.length && c.abs<tbl[r].length }
puts CSV.generate(**opts){|csv| tbl.each{|r| csv<<r } }
' '[ [[2,1],1], [[0,2],-3], [[-1,0],1.2] ]' file.tsv
Prints:
0 0 -3 0
0 0 0 0
0 1 0 0
1.2 0 0 0
Keep in mind that Ruby arrays are 0
based so row 3, col 2 would be expressed as [2,1]
. The reference [-1,0]
means last row, first column; any negative index is counting backwards from the array end in Ruby.
This might work for you (GNU sed and shell):
r=3 c=2
sed -E $r'{s/[0-9]+/$((&+1))/'$c';s/.*/echo "&"/e}' file
Assign 3
to r
and 2
to c
for row 3, column 2.
Increment the second column of numbers by one for the third row only and echo the evaluated result.