awk 中的命令行参数

awk 中的命令行参数

我只想在 awk 中实现 if 条件。我创建了一个文件名:“simple_if”,如下所示。

BEGIN{
num=$1;
if (num%2==0)
printf "%d is Even number.\n",num;
else printf "%d is odd Number.\n",num
}

然后我通过传递 10 作为 $1 的参数来执行程序,如下所示

awk -f simple_if 10

但它不接受输入,而是显示 0。输出:

0 is Even number.

如何在awk中从用户那里获取价值?

答案1

命令行末尾给出的参数awk通常被视为awk脚本将从中读取的文件名。要在命令行上设置变量,请使用-v variable=value,例如

awk -v num=10 -f script.awk

这将使您能够num在脚本中用作变量。在上面的示例中,变量的初始值为 10。

您还可以ENVIRON["variable"]在脚本中使用读取环境变量(对于某些名为 的环境变量variable),或者查看命令行参数,其中ARGV[n]wheren是某个正整数。


使用$1in awk,您将引用当前记录中第一个字段的值,但由于您在块中使用它BEGIN,因此尚未从任何文件中读取任何数据。

代码中的数字被解释为零,因为它是算术上下文中使用的空变量。

答案2

$1不是第一个命令行参数,而是该行被分割后的第一个字段FS(并且它将是 中的空字符串BEGIN,因为尚未分割任何行)。

命令行参数位于数组中ARGV

$ awk 'BEGIN { for(i = 1; i < ARGC; i++) print ARGV[i] }' 1st 2nd 3rd
1st
2nd
3rd

ARGV[0]始终是解释器的名称(awkgawk等)。

为了让awk忽略命令行参数并且稍后不尝试将其作为文件打开,您应该删除它或将其设置为空字符串:例如。ARGV[1]=""

作为旁注,该形式的任何参数var=value也将被解释为 , 的变量赋值awk,并将被 eval'ed它之前的文件参数已经被处理:

$ echo yes > file
$ awk '{ gsub(/e/, var); print }' var=1 file var=2 file var=3 file
y1s
y2s
y3s

要使用 形式的实际文件名key=valawk您应该将其作为相对或绝对路径传递,例如。awk '{...}' ./key=val

答案3

我想指出user313992中提到的一个关键点回答

为了让 awk 忽略命令行参数并且稍后不尝试将其作为文件打开,您应该删除它或将其设置为空字符串:例如。 ARGV[1]=""。

根据 POSIX awk文档,论证可以仅有的以两种形式之一解释:

  1. 要读入的文件
  2. 作业形式:var=val

因此,如果指定的参数不是现有文件,并且不在分配表单中,仅有的阅读该参数后,awk 将失败:

BEGIN {
 # this is OK:
 for (i=1; i<ARGC; i++) {
  print "+++ ", ARGV[i]
}

# action blocks will fail, because file reading has started
{
  print $1
}

因此,可以将不存在的参数指定为文件,但是,必须记住在ARGV操作块之前删除它们。

例子 -

#!/bin/awk -f
#
# Bin count using thresholds given at argv. E.g.
# 
#   ./bin_count 0.1 0.01 0.001 0.0001 <./data | sort
#   < 0.000100: 3
#   < 0.001000: 12
#   < 0.010000: 56
#   < 0.100000: 100

BEGIN {
    for (i=1; i<ARGC; i++) counts[ARGV[i]] = 0
    delete ARGV    # <<<<< important
}
{
    $1 = $1 < 0 ? -$1 : $1
    for (bin in counts) {
        if ($1 < bin) { counts[bin]++; }
    }
}
END {
    for (bin in counts) {
        printf("< %f: %d\n", bin, counts[bin])
    }
}

答案4

与任何其他类似 C 的程序一样,常规 Awk 处理命令行参数没有问题,而无需求助于任何 GNUgawk特定行为、管道或重定向 ( <) 或-v(变量赋值)选项。

输入参数的处理ARGC(参数数数,一个整数)和ARGV(参数向量,“列表”的另一个词)都在手册

Mosvy 很好地解释了背景,并总结了解析ARGV.这是您最初的目标,作为独立的 shell 脚本实现,并在 macOS 和 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;
    }
}

制作一个像这样的 awk 脚本可执行文件使用chmod a+x scriptname.awk,将其放入您的 中$PATH,它可以像任何其他 Bash、Python、Perl 脚本、C 程序等一样运行。

如果awk存在于系统上的其他位置,请#!适当更新该行;它可能无法使用,/usr/bin/env因为awk 必须-f选择运行您的脚本,并且...情况很复杂

.awk名不是必需的根本不,但它可能会帮助您的编辑器启用正确的语法突出显示。将其关闭,甚至没有人需要知道它是一个 Awk 脚本。


这是一个更完整的示例,它做了一些有用的事情,并且具有合理的错误处理:

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
}

相关内容