我只想在 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
是某个正整数。
使用$1
in 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]
始终是解释器的名称(awk
或gawk
等)。
为了让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=val
,awk
您应该将其作为相对或绝对路径传递,例如。awk '{...}' ./key=val
。
答案3
我想指出user313992中提到的一个关键点回答。
为了让 awk 忽略命令行参数并且稍后不尝试将其作为文件打开,您应该删除它或将其设置为空字符串:例如。 ARGV[1]=""。
根据 POSIX awk文档,论证可以仅有的以两种形式之一解释:
- 要读入的文件
- 作业形式:
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
}