5

While working on a script, the following script gave an error

file * | awk '{ ${1}=""; print substr(${0},2) }';

while both of the following scripts ran successfully

file * | awk '{ $"1"=""; print substr($"0",2) }';

and

file * | awk '{ $1=""; print substr($0,2) }';

Aren't $1, ${1}, $"1" all parameter substitution? Is there a problem with my awk syntax?

  • 1
    Note that one of the reasons the curly braces are not used under awk but required under the shell is when the positional parameter is larger than 9. Under the shell $10 is $1 immediately followed by the letter 0 while under awk, it's the tenth field. – jlliagre Jul 1 '17 at 8:16
11

awk is not the shell. awk has its own grammar, syntax and semantics. ${1} is not syntactically correct awk code while both $1 and $"1" are (and these are equivalent in awk). In awk, these are not substitutions.

With awk, $1 refers to the first field of the current input record and $0 refers to the complete input record, while in the shell, $1 refers to the first positional parameter (usually the first argument on the command line of a script or function) and $0 usually refers to the name of the current shell or shell script.

Shell variables and awk variables are also completely separate. This is why awk has the -v command line flag to set its variables if you need to "import" a value from the shell to your awk script:

$ awk -v var="$var" '{...}'

You may also give an awk script a the value of a shell variable like this:

$ awk '{...}' var="$var"

This is almost the same thing as doing it with -v except that the variable var will be empty in any BEGIN block. A BEGIN block is executed before looking at the input data, and the variable is set after the execution of such a block.

You can also do

$ awk '{...}' var="$value1" file1 var="$value2" file2

This makes the var variable get the value of the shell variable $value1 just before file1 is being processed, and then the value of the shell variable $value2 just before file2 is being processed.

If any file has the name var="$value1" in the last example (for example var="42", which is a perfectly legal Unix filename), that file will not be processed. Also if a shell filename globbing pattern on the command line picks up a file whose name looks like an assignment to a variable, this assignment will be active in the awk script.

  • 2
    Also $ 1, $(0+2/2), $ length("a"). It's important to realise $ is an operator, not a parameter introducer like in shells. – Stéphane Chazelas Aug 22 '17 at 13:09
  • One should avoid -v to import variables from the shell, as it mangles the values if they contain backslashes. Using the environment and the ENVIRON special hash in awk is preferable. – Stéphane Chazelas Aug 22 '17 at 13:10
  • 1
    Replying to myself, actually it seems $ "1st field" is like $1 everywhere except in GNU awk. Looking at the POSIX spec, it's not clear what that or $"1" are meant to yield. The gawk behaviour seems buggy to me. Compare echo a b | awk '{print $("" "1st")}' and echo a b | awk '{print $("1st")}' for instance. – Stéphane Chazelas Aug 22 '17 at 13:23
  • 1
    Looking at the git HEAD of gawk, $"1" no longer works there actually. – Stéphane Chazelas Aug 22 '17 at 13:39
  • 1
    I just raised the question on the austin-group mailing list mail-archive.com/austin-group-l@opengroup.org/msg01543.html – Stéphane Chazelas Aug 22 '17 at 14:48

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.