0

I have a number of variables in a .dat file that I automatically changed with a script. One of these files has a parameter, bar, that is arranged as such in a .dat file:

var1  var2   var3  foo  bar
T     T      T     100  100

I used to use the following lines of a bash script to change the value of bar from an arbitrary initial value to the desired value, in this case 2000. This script would change 'bar' to 2000.

LINE1=$(awk '/bar/ {++n;if (n==1) {print FNR}}' data.dat)
((LINE1=$LINE1 + 1))
OLD1=$(awk '{for(i=1;i<'$LINE1';i++) getline}{print $12}' data.dat)
sed -i '' "${LINE1}s/$OLD1/2000/" data.dat

However, I now must now change foo alongside bar. In this example, this is setting foo and bar both to 2000.

LINE1=$(awk '/foo/ {++n;if (n==1) {print FNR}}' data.dat)
((LINE1=$LINE1 + 1))
OLD1=$(awk '{for(i=1;i<'$LINE1';i++) getline}{print $12}' data.dat)
sed -i '' "${LINE1}s/$OLD1/2000/" data.dat

LINE1=$(awk '/bar/ {++n;if (n==1) {print FNR}}' data.dat)
((LINE1=$LINE1 + 1))
OLD1=$(awk '{for(i=1;i<'$LINE1';i++) getline}{print $12}' data.dat)
sed -i '' "${LINE1}s/$OLD1/2000/" data.dat

This instead only changed the foo to 2000 while leaving bar unchanged. I realize that this is an issue with the way I've described the regular expression, but I have been unable to change both variables with an awk/sed expression.

  • Pls post the file fort.4 so people can follow your logics. Do you want to change the bar text or the number 100? – RudiC Sep 20 '18 at 16:18
  • The fort.4 was an accidental insertion, the file to be edited is data.dat. The var 1/var 2/var 3/ lines are now representative of the data.dat file. I'm trying to change the arguments to foo and bar rather than the strings foo and bar – eoncarlyle Sep 20 '18 at 18:04
0

You can do

awk -v newvalue=2000 '
    NR == 1 {
        for (i=1; i<=NF; i++) {
            if ($i == "foo") i_foo=i
            if ($i == "bar") i_bar=i
        }
    }
    NR == 2 {$i_foo = $i_bar = newvalue}
    {print}
' file.dat | column -t
var1  var2  var3  foo   bar
T     T     T     2000  2000

Or, with less hard-coding in the awk

awk -v cols="var2=1234,bar=5678" '
    BEGIN {
        n = split(cols, a, /[=,]/)
        for (i=1; i<n; i+=2) newval[a[i]] = a[i+1]
    }
    NR == 1 { for (i=1; i<=NF; i++) if ($i in newval) idx[$i] = i }
    NR == 2 { for (col in idx) $(idx[col]) = newval[col] }
    {print}
' file.dat | column -t
var1  var2  var3  foo  bar
T     1234  T     100  5678
  • Is there a way to do this to in-place change file.dat? – eoncarlyle Sep 22 '18 at 16:08
  • With GNU awk gawk -i inplace '... – glenn jackman Sep 22 '18 at 23:25
0

Just for fun:

awk -F'\t' -vOFS='\t' -vfoovalue=2101 -vbarvalue=2102 '
             /foo/&&/bar/{
                           row=NR
                           for(i=1;i<=NF;i++){
                                               if($i=="foo"){colfoo=i}
                                               if($i=="bar"){colbar=i}
                                              }
                           print
                          }
             NR==row+1{ $colfoo=foovalue; $colbar=barvalue; print }
            ' file

var1    var2    var3    foo         bar
T       T       T       2101        2102

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.