0

I have a file that looks like this:

AABBCC 10
DDEEFF 20
etc

I need to find a line containing let's say AABBCC and replace the number after it. I do it with awk:

awk -i inplace '{if($1=="AABBCC") {$2="30"} print $0}' myfile.txt

and it works perfectly fine

However when I do this like so inside a script

awk -i inplace '{if($1==$A) {$2=$B} print $0}' myfile.txt

it isn't working.

I've tried commas around $A and $B to no success. Any thoughts? My bash is GNU bash, version 5.0.17(1)

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • Where are `A` and `B` defined in the second version?? `$A` says "awk find that variable named `A` and give me the value of the field with its value (`$A`)" I don't see `A` or `B` given a value anywhere. When a variable like `A` or `B` are used undefined, `awk` simply initializes the value `0` – David C. Rankin Apr 02 '23 at 07:54
  • It's just a snippet: #!/bin/bash A=AABBCC B=30 awk -i inplace '{if($1==$A) {$2=$B} print $0}' myfile.txt – Damien Lazovsky Apr 02 '23 at 07:55
  • That's what I'm saying `$A` `awk` variable and `$A` script variable are two different things. See how the `awk` script is run between single-quotes? Variable expansion (from a bash-script standpoint) does not occur. So your `awk` script sees `$A` and says `0`. You can either `-v A=1 -v B=3` or use the `BEGIN` rule, e.g. `awk 'BEGIN {A=1; B=3} {if($1==$A) {$ ...}' myfile.txt` Yes, you can use script variables with `-v A="$var1" -v B="$var2"` – David C. Rankin Apr 02 '23 at 07:58
  • So that would be `awk -v A="AABBCC" -v B=30 -i inplace '{if($1==$A) {$2=$B} print $0}' myfile.txt` – David C. Rankin Apr 02 '23 at 08:02
  • Shell quoting rules: Single quotes prevent parameter expansion. Therfore, `$A` is not expanded in your code, which is fortunate, because expansion would yield wrong code here anyway. You can use either the `-v` option to assign a shell variable to a awk variable (as David Rankin explained), or alternatively first turn your shell variable into a environment variable (using `export`) and use inside awk the predefined array `ENVIRON` to access them. – user1934428 Apr 03 '23 at 06:35

2 Answers2

2

The below script works and gives you desired output:

awk -i inplace '{if($1==A) {$2=B} print $0}' A="$A" B="$B" myfile.txt

More about how shell variable works in awk: https://linuxhint.com/awk_command_variables/

Hope this helps. Thanks.

Suchandra T
  • 569
  • 4
  • 8
1

In your second version, e.g.

awk -i inplace '{if($1==$A) {$2=$B} print $0}' myfile.txt

$A and $B are awk variables, not shell variables. Note how the awk script is run between single-quotes -- shell variable expansion does not occur. So awk sees $A which it has no value for and simply initializes the variable as 0.

In awk, you can either pass variable values with the -v option or use the BEGIN{ ... } rule to do it. Since you are wanting to use shell variables per-your comment, you will need to use the -v form, e.g.

awk -v A="AABBCC" -v B=30 -i inplace '{if($1==$A) {$2=$B} print $0}' myfile.txt

(note: using $A with AABBCC would make no sense as it wouldn't correspond to a valid field in your input, but using just A could. Now with B=30, that may correspond to the 30th field, but if you have less than 30 fields, then it would be B and not $B -- the $ prefix in awk indicating the value of the variable corresponds to a specific field of input -- for which you want its value)

Now awk knows what A is and what B is.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85