7

assume I have a string

"1,2,3,4"

Now I want to replace, e.g. the 3rd field of the string by some different value.

"1,2,NEW,4"

I managed to do this with the following command:

echo "1,2,3,4" | awk -F, -v OFS=, '{$3="NEW"; print }'

Now the index for the column to be replaced should be passed as a variable. So in this case

index=3

How can I pass this to awk? Because this won't work:

echo "1,2,3,4" | awk -F, -v OFS=, '{$index="NEW"; print }'
echo "1,2,3,4" | awk -F, -v OFS=, '{$($index)="NEW"; print }'
echo "1,2,3,4" | awk -F, -v OFS=, '{\$$index="NEW"; print }'

Thanks for your help!

Peter Meier
  • 483
  • 3
  • 7
  • 17

5 Answers5

7

This might work for you:

index=3 
echo "1,2,3,4" | awk -F, -v OFS=, -v INDEX=$index '{$INDEX="NEW"; print }'

or:

index=3 
echo "1,2,3,4" | sed 's/[^,]*/NEW/'$index
potong
  • 55,640
  • 6
  • 51
  • 83
  • how is it done if "NEW" is assigned to a variable? this is not working: `sed 's/[^,]*/$var/'$index` – dcdum2018 Oct 28 '21 at 13:30
  • 1
    @dcdum2018 notice the double quotes. – potong Oct 28 '21 at 13:39
  • i tried these: `echo $line | awk -F, -v OFS=, -v INDEX=$index '{$INDEX="$var"; print}'` and `echo $line | sed 's/[^,]*/$var/'$index`, but both are literally replacing with `$var` – dcdum2018 Oct 28 '21 at 13:54
  • 1
    @dcdum2018 single quotes prevents interpolation therefore either use double quotes or put the shell variable outside of the single quotes e.g. `sed "s/[^,]*/$var/$index" file1` or `sed 's/[^,]*/'$var'/'$index file` – potong Oct 28 '21 at 14:13
  • it worked well! thank you! if it isn't much, could you please have a look on my question here? :) https://stackoverflow.com/questions/69751857/remove-last-character-using-for-loop – dcdum2018 Oct 29 '21 at 01:54
5

Have the shell interpolate the index in the awk program:

echo "1,2,3,4" | awk -F, -v OFS=, '{$'$index'="NEW"; print }'

Note how the originally single quoted awk program is split in three parts, a single quoted beginning '{$', the interpolated index value, followed by the single quoted remainder of the program.

Jens
  • 69,818
  • 15
  • 125
  • 179
  • 1
    You can use `-v var=value` to define a variable inside awk through its command line and then use `$var`. So this text substitution hack is not needed. – Kaz Mar 24 '12 at 18:30
2

Here's a seductive way to break the awkwardness:

$ echo "1,2,3,4" | sed 's/,/\n/g' | sed -e $index's/.*/NEW/'

This is easily extendable to multiple indexes just by adding another -e $newindex's/.*/NEWNEW/'

Lev Levitsky
  • 63,701
  • 20
  • 147
  • 175
  • How can I convert the newlines back to a comma-separated list? I tried sed 's/\n/,/g' but that won't work? – Peter Meier Mar 23 '12 at 12:55
  • @PeterMeier, I think it doesn't work because `sed` treats lines separately now, not as a whole text. Having looked at [this answer](http://stackoverflow.com/a/6539865/1258041), I suggest piping the output to `paste -sd ','` like this: `echo "1,2,3,4" | sed 's/,/\n/g' | sed -e $index's/.*/NEW/' | paste -sd ','`. – Lev Levitsky Mar 23 '12 at 17:48
0
# This should be faster than awk or sed.
str="1,2,3,4"
IFS=','
read -a f <<< "$str"
f[2]='NEW'
printf "${f[*]}"
baz
  • 1,317
  • 15
  • 10
-1

With plain awk (I.E. Not gawk etc) I believe you'll have to use split( string, array, [fieldsep] ); change the array entry of choice and then join them back together with sprintf or similar in a loop.

gawk allows you to have a variable as a field name, $index in your example. See here.

gawk is usually the default awk on Linux, so change your invocation to gawk "script" and see if it works.

JimR
  • 15,513
  • 2
  • 20
  • 26