Regular Awk has no problem processing command line arguments as any other C-like program would, without resorting to any GNU gawk
-specific behavior, pipes or redirection (<
), or the -v
(variable assignment) option.
The handling of input arguments, ARGC
(the argument count, an integer), and ARGV
(the argument vector, another word for "list") are all covered in great detail in the manual.
Mosvy did a great job explaining the background, and summarizing what needs to be done to parse ARGV
. Here is your original objective, implemented as a standalone shell script, tested on both macOS and GNU/Linux.
simple_if.awk
#!/usr/bin/awk -f
##
## simple_if - tell user if a number given as an argument is even or odd
##
## Example: ./simple_if.awk 11
##
BEGIN {
num = ARGV[1];
# if you expect to arguments AND read from one or more input files, you need
# to remove the arguments from ARGV so Awk doesn't attempt to open them as
# files (causing an error)
#ARGV[1] = "";
if (num % 2 == 0) {
printf "%d is an even number.\n", num;
} else {
printf "%d is an odd number.\n", num;
}
}
Make an Awk script like this executable with chmod a+x scriptname.awk
, put it in your $PATH
, and it can run just as any other Bash, Python, Perl script, C program, whatever.
If awk
exists on some other place on your system, update the #!
line appropriately; it may not be possible to use /usr/bin/env
because awk
must have the -f
option to run your script, and… it's complicated.
The .awk
extension isn't necessary at all, but it may help your editor to enable proper syntax highlighting. Leave it off and no one even needs to know it's an Awk script.
Here's a more complete example that does something useful, and has reasonable error-handling:
simple_stats.awk
#!/usr/bin/awk -f
##
## simple_stats - do simple 1-variable statistics (min/max/sum/average) on
## the first column of its input file(s)
##
## examples: ./simple_stats min numbers.txt
## ./simple_stats all numbers.txt # all stats
## ./simple_stats sum <(du MyFiles) # Bash proc. substitution
##
## # specify '-' as the filename when reading from stdin
## seq 1 100 | ./simple_stats avg -
##
BEGIN {
# expect stats operation as the first argument
op = ARGV[1]
# unset this array index so Awk doesn't try opening it as a file later
# ref: https://www.gnu.org/software/gawk/manual/html_node/ARGC-and-ARGV.html
ARGV[1] = ""
# if you wanted to process multiple command line arguments here, you could
# loop over ARGV, using something like
# for (i=0; i<ARGC; i++) { if (ARGV[i] == "...") { ... } }
if (op !~ /^(min|max|sum|avg|all)$/) {
print "ERROR: Expected one of min/max/sum/avg/all." >"/dev/stderr"
# 'exit' in BEGIN will always run the EXIT block, if one exists
# see https://www.gnu.org/software/gawk/manual/html_node/Assert-Function.html
_assert_exit = 1
exit 1
}
# ordinarily Awk reads stdin without specifying; here, '-' seems necessary
if (ARGV[2] == "") {
print "ERROR: Need an input file (or '-' for stdin)." >"/dev/stderr"
_assert_exit = 1
exit 1
}
}
# 'min' needs an initial value so take the first record
NR == 1 { min = $1 }
# for every input line (including the first)...
{
sum += $1
if ($1 > max) max = $1
if ($1 < min) min = $1
}
END {
if (_assert_exit) exit 1; # if 'exit' was pending from BEGIN block
if (op == "min" || op == "all")
printf "The minimum is: %15d\n", min
if (op == "max" || op == "all")
printf "The maximum is: %15d\n", max
if (op == "sum" || op == "all")
printf "The sum is: %15d\n", sum
if (op == "avg" || op == "all")
printf "The average is: %15.2f\n", sum/NR
}
ARGV
array) with Bash / Bourne shell positional parameters ($1
,$2
, and so on). Awk uses$1
,$2
, and so on to refer to the individual "fields" of an input line, after splitting on whitespace (by default), as best explained in mosvy's answer below. These are like the columns (A, B, C, and so on) in a spreadsheet program, except numbers instead of letters. – Kevin E Feb 12 '20 at 08:08