3

I was doing some data filtering and noticed something a bit strange.

As we all know, awk '1' is short for awk '{print $0}', since 1 evaluates to True and triggers that default action on Awk, which consists on printing the current record.

Similarly, awk '0' does not print anything because it evaluates to False.

$ seq 3 | awk '0'
                      # nothing
$ seq 3 | awk '1'
1
2                     # everything
3

So I tried different approaches on this and noticed that awk '-1' gives an error, while awk '(-1)' works without a problem:

$ seq 3 | awk '-1'
Usage: awk [POSIX or GNU style options] -f progfile [--] file ...
Usage: awk [POSIX or GNU style options] [--] 'program' file ...
POSIX options:      GNU long options: (standard)
...
        # all the gawk explanation on how to use it
...
$ seq 3 | awk '(-1)'
1
2                     # everything, since apparently
3                     # -1 evaluates to True

The same with awk '-NF' or awk '-NR' or any other expression starting with the negative character.

Why is this?

I am on GNU Awk 4.1.65, API: 2.0.

jub0bs
  • 60,866
  • 25
  • 183
  • 186
fedorqui
  • 275,237
  • 103
  • 548
  • 598
  • 4
    not strictly an issue with awk... just how options are processed... try `seq 3 | awk -- '-1'` and `seq 3 | grep '-1'` .. there's an duplicate somewhere.. – Sundeep May 17 '18 at 08:34
  • @Sundeep: I agree with you, `awk '-1' ` will be interpreted as option `-1` that does not exist therefore the help page is displayed, however I can not explain the behavior of `seq 3 | awk '(-1)'` would bash interpret `(-1)`? – Allan May 17 '18 at 08:35
  • 1
    @Allan since `-` is not first character, `'(-1)'` is no longer considered as option.. so then it comes to awk.. `()` is useful in expression in case of operator precedence, clarity etc.. here, it just evaluates to `-1` – Sundeep May 17 '18 at 08:40
  • @Sundeep thanks for seeing what the error is! – fedorqui May 17 '18 at 08:43
  • 1
    also, in case someone's wondering, `awk '1'` is same as `awk 1`.. the quotes are used to avoid having to deal with shell special characters like space, `$`, globs, etc and a typical awk one liner is gonna have those.... `awk '-1'` is same as `awk -1` ... – Sundeep May 17 '18 at 08:47
  • @fedorqui fair enough, will try to search duplicate for that.. I don't know if this is specific to GNU tools as well.. I don't know how these tools are written, I'm guessing they'll be using modules like getopts.. in short, any non-option argument starting with `-` will require special attention unless the tool has a way to distinguish it.. – Sundeep May 17 '18 at 08:51
  • @fedorqui does this help? https://stackoverflow.com/questions/36495669/difference-between-terms-option-argument-and-parameter – Sundeep May 17 '18 at 08:55
  • @Sundeep it explains it very well. Since it is not straightforward, would you mind answering with a little post explaining the issue and linking to that other question? I will of course vote to close as dupe of that – fedorqui May 17 '18 at 08:58

1 Answers1

3
seq 3 | awk '-1'

is same as

seq 3 | awk -1

single/double quotes can be used to construct an argument on command line depending on what's needed, for ex:

$ echo 'foo baz' | grep 'foo b'
foo baz
$ echo 'foo baz' | grep foo\ b
foo baz

$ echo 'foo:baz:123' | awk '-F:' '{print $1}'
foo
$ f='-F:'; echo 'foo:baz:123' | awk "$f" '{print $1}'
foo
$ var='$1'; echo 'foo:baz:123' | awk '-F:' "{print $var}"
foo

Coming back to awk -1, the -1 gets treated as an option (because options start with - or -- depending on tool). -1 is not a valid option, so we get an error

Most tools have a workaround for such cases, using -- will indicate no further option

$ seq 3 | awk -- -1
1
2
3

More examples:

$ # echo is fine with echoing non-options starting with -
$ echo '-1'
-1
$ echo '-1' | grep '-1'
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.
$ echo '-1' | grep -- '-1'
-1

$ echo 'Foo' | grep 'foo'
$ # using option at end depends on tool, I think it is GNU specific
$ echo 'Foo' | grep 'foo' -i
Foo
$ echo 'Foo' | grep -- 'foo' -i
grep: -i: No such file or directory

Further reading: Difference between terms: "option", "argument", and "parameter"?

Sundeep
  • 23,246
  • 2
  • 28
  • 103
  • 1
    You can also mention `var='$1'; echo 'foo:baz:123' | awk '-F:' "{print $var}"`, where the expression in Awk is within double quotes so it expands the Bash variable in it. – fedorqui May 18 '18 at 09:04