srinivas yelamanchili
srinivas yelamanchili

Reputation: 61

unix sed, replace field at a specific row and column in the same file

I have a text file with 4 columns delimited by comma. As I am reading each record in a loop, I want to add a value to the 5th column depending on a condition. So if I know the row number and column number, how can I use awk/sed commands to replace/set value at that particular field without using temporary files? I want to update the file (directly) that I am reading from

inp.txt
a,b,c,d
e,f,g,h
i,j,k,l

Thanks, -sri

Upvotes: 0

Views: 24838

Answers (4)

William Pursell
William Pursell

Reputation: 212218

You cannot directly edit the file with either awk or sed. Some versions of sed have an option (-i) that works with a temporary file and overwrites the original file, but it does not actually edit the file in place. This is not a big deal. Just do:

$ awk 'NR==5{ $(NF+1) = "new value"}1' OFS=, FS=, input-file > tmp.$$
$ mv tmp.$$ input-file

To add a new column to row 5 of input-file. If you wish, you can use ed to edit the file, but it makes more sense to use a temporary file. If you want to pretend that you aren't using a temporary file, and your sed supports -i, you can do the same thing with:

sed -i '5s/$/,new value/' input-file

Even though most utilitites do not allow in-place modification of the file, it is simple to use one of the following sh functions to emulate that behavior using temporary files:

edit() { local f=$1; shift; "$@" < $f > $f.$$ && mv $f.$$ $f; }  # Break hard links
edit() { local f=$1; shift; "$@" < $f > $f.$$ && cat $f.$$ > $f && rm $f.$$; }

With either of these, you could use awk to give the appearance of editing files in-place using edit filename awk awk-cmds. The first version breaks hard links, but uses slightly less IO.

Upvotes: 2

Vijay
Vijay

Reputation: 67211

perl -i -F, -lane 'if($.==<row number>){$F[<column_number>-1]+=<add your stuff here>}print join(",",@F)' your_file

tested below:

>cat temp
b,c,d,g
r,g,d,s

execute for changing the 3rd column in second row:

>perl -i -F, -lane 'if($.==2){$F[2]=10}print join(",",@F)' temp
> cat temp
b,c,d,g
r,g,10,s

Upvotes: 1

tsohr
tsohr

Reputation: 915

You mean like this? this is the version don't using any temporary files.

[a@b ~]$ cat tmp | sed 's_^\(.*\),\(.*\),\(.*\),\(.*\)_\1,\2,\3,\4_g' 
inp.txt
a,b,c,d
e,f,g,h
i,j,k,l

[a@b ~]$ cat tmp | sed 's_^\(.*\),\(.*\),\(.*\),\(.*\)_\1,sth,\3,\4_g'
inp.txt
a,sth,c,d
e,sth,g,h
i,sth,k,l

[a@b ~]$ sed -ie 's_^\(.*\),\(.*\),\(.*\),\(.*\)_\1,sth,\3,\4_g' tmp
[a@b ~]$ cat tmp
inp.txt
a,sth,c,d
e,sth,g,h
i,sth,k,l

Cheers,

Upvotes: 0

zzk
zzk

Reputation: 172

I can't speak for sed, but the purpose of awk isn't to edit files in place but to write to stdout.

But anyway, here's a solution you don't need a loop for, pretending the condition is that the entry in column 4 is an h.

awk -F ',' '{ if ($4 == "h") print $0",z"; else print $0","}' inp.txt > out.txt

output:

a,b,c,d,
e,f,g,h,z
i,j,k,l,

Upvotes: 2

Related Questions