Philip Kearns
Philip Kearns

Reputation: 419

Cannot use Awk with arguments

I am trying to argument processing on awk. It works fine if I have no body in it:

PK@rhel8:~/tmp-> cat testARG.awk 
#!/usr/bin/awk -f
BEGIN{
argc = ARGC ;
CmdName = ARGV[0] ;
FirstArg = ARGV[1]      
printf("Argument count = %d; command name = %s; first argument = %s\n",argc,CmdName,FirstArg) ;
}
#{
#   printf("Argument count = %d; command name = %s; first argument = %s\n",argc,CmdName,FirstArg) ;
#   print $0
#}
PK@rhel8:~/tmp-> ./testARG.awk 1 2 3 4
Argument count = 5; command name = awk; first argument = 1
PK@rhel8:~/tmp-> 

However when I uncomment the body it doesn't like it at all:

PK@rhel8:~/tmp-> cat testARG.awk 
#!/usr/bin/awk -f
BEGIN{
argc = ARGC ;
CmdName = ARGV[0] ;
FirstArg = ARGV[1]      
printf("Argument count = %d; command name = %s; first argument = %s\n",argc,CmdName,FirstArg) ;
}
{
    printf("Argument count = %d; command name = %s; first argument = %s\n",argc,CmdName,FirstArg) ;
    print $0
}
PK@rhel8:~/tmp-> ./testARG.awk 1 2 3 4
Argument count = 5; command name = awk; first argument = 1
awk: ./testARG.awk:6: fatal: cannot open file `1' for reading (No such file or directory)
PK@rhel8:~/tmp-> 

Is there some different way I have to use awk to allow it to see the arguments as arguments and not files?

Upvotes: 1

Views: 111

Answers (3)

Ed Morton
Ed Morton

Reputation: 204719

It's not entirely clear what you want to do since you're passing numbers to your Unix command and apparently don't want any of them treated as file names, but then your uncommented code relies on having an input file to process.

I'm assuming since you have a part of your script operating line by line printing $0 that you'll pass a file name for awk to work on as the final argument to your command but you want the command arguments before that last one to not be treated as files.

Given that, here's how to write a Unix command to see initial arguments to it as values to be passed to your awk script and not as files without changing the interface to your script and without tightly coupling it to being implemented in awk:

$ cat testArg
#!/usr/bin/env bash

args="${*:1:$#-1}"
shift $(( $# - 1 ))

awk -v args="$args" '
    BEGIN{
        argc = split(args,vals)
        CmdName = ARGV[0] ;
        FirstArg = vals[1]
        printf("Argument count = %d; command name = %s; first argument = %s\n",argc,CmdName,FirstArg) ;
    }
    {
        printf("Argument count = %d; command name = %s; first argument = %s\n",argc,CmdName,FirstArg) ;
        print $0
    }
' "${@:--}"

$ seq 2 > file

$ ./testArg 1 2 3 file
Argument count = 3; command name = awk; first argument = 1
Argument count = 3; command name = awk; first argument = 1
1
Argument count = 3; command name = awk; first argument = 1
2

Note that with this approach you don't need do modify your desired command line in any way, including having anything awk-specific on the command-line when you call your script, and if you decide to replace awk with perl or a compiled C program or anything else inside your script you don't need to change the script's API nor any of the places it's called from.

Upvotes: 1

Philip Kearns
Philip Kearns

Reputation: 419

The fix is to add a -:

PK@rhel8:~/tmp-> ./testARG.awk - 1 2 3 4
Argument count = 6; command name = awk; first argument = -
howdy
Argument count = 6; command name = awk; first argument = -
howdy
^C
PK@rhel8:~/tmp->

Of course I have to move the arguments down by one to skip the -. However it still gets confused if you use ^D instead of ^C:

PK@rhel8:~/tmp-> ./testARG.awk - 1 2 3 4 
Argument count = 6; command name = awk; first argument = -
howdy
Argument count = 6; command name = awk; first argument = -
howdy
howdy there
Argument count = 6; command name = awk; first argument = -
howdy there
awk: ./testARG.awk:10: fatal: cannot open file `1' for reading (No such file or directory)
PK@rhel8:~/tmp-> 

Not sure how the coders intended it to be used. So it would appear the solution suggested @markp-fuso is better choice.

Upvotes: 2

markp-fuso
markp-fuso

Reputation: 35516

You may want to get used to a more standard way of passing non-file args to awk. A common method is to define awk variable assignments on the command line. The general format:

awk -v awk_var1="OS val 1" -v awk_var2="OS val 2" '... awk script ...' [ optional list of filenames]

# or

./script.awk -v awk_var1="OS val 1" -v awk_var2="OS val 2" [ optional list of filenames]

If you won't be processing any files then all processing within the awk script will need to take place within the BEGIN{} block.

Since the current script is looking to count input args and print the 'first', I take it to mean the number of input args could be variable. One common approach would be to provide the args in a single delimited string, eg:

$ cat testARG.awk 
#!/usr/bin/awk -f
BEGIN { n=split(inlist,vars,";")           # split awk input variable "inlist" on a ";" delimiter and put results in the vars[] array; split() returns the number of entries in the array, we save this count in awk variable "n"
        CmdName = ARGV[0]
        printf "Argument count = %d; command name = %s; first argument = %s\n", n, CmdName, vars[1]
      }

$ ./testARG.awk -v inlist="1;2;3;4"        # define awk variable "inlist" as a ";"-delimited list of values
Argument count = 4; command name = awk; first argument = 1

Upvotes: 2

Related Questions