Search code examples
awkgnugawk

Why does '-1' not work in Awk but '(-1)' does?


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.


Solution

  • 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"?