我想编写一个相当复杂的AWK脚本,该脚本将使用一堆命令行参数,解析它们,然后执行一些工作。
不幸的是,尝试将短划线(-arg
)参数传递给脚本时遇到麻烦,因为它们由AWK解释。
$ ./script.awk -arg
awk: not an option: -arg
我注意到了--
选项,但是我不确定如何在shebang中有意义地使用它。我找不到任何方法来获取文件名并在脚本的shebang中引用它(类似#!/usr/bin/awk -f $FILE --
)。
然后我想也许可以使用-W exec
选项来解决此问题,但是我不断收到以下错误(即使没有尝试将--
选项都使用),这似乎表明该文件的名称甚至没有真正附加到shebang命令的末尾。
$ ./script.awk
awk: vacuous option: -W exec
awk: 1: unexpected character '.'
是否有一种方法可以制作一个独立的(单个文件,没有包装脚本)可执行的AWK脚本,该脚本可以接受短划线前缀的参数?
为什么我要在这种程度上滥用AWK?出于好奇,通常是为了摆脱包装程序外壳程序脚本,我目前仅需使用该脚本来执行AWK脚本:
#!/bin/sh
awk -f script.awk -- "$@"
该解决方案应符合POSIX(假定AWK的路径为/usr/bin/awk
)。即使您有不兼容POSIX的解决方案,也请共享它。
答案 0 :(得分:2)
了解问题所在:
据我了解,OP具有一个名为script.awk
的复杂脚本:
#!/usr/bin/awk -f
BEGIN{print "ARGC", ARGC; for(i=0;i<ARGC;++i) print "ARG"i,ARGV[i]}
OP希望使用各种传统POSIX样式的一个字母选项或GNU样式的long选项调用的。 POSIX选项以单个-
)开头,而长选项以两个--
)开头。但是,这失败了,因为awk解释了将要传递给awk本身而不是脚本参数列表的这些参数。例如
$ ./script.awk
ARGC 1
ARG0 awk
$ ./script.awk -arg
awk: not an option: -arg
问题:是否可以编写一种兼容POSIX的脚本来处理这种带有连字符的参数? (建议是在原始问题中提出的。)
观察1:虽然没有立即清除,但必须指出,错误消息是由 mawk 生成的,而不是由更常见的GNU版本 gawk 强>。当mawk失败时,gawk不会:
$ mawk -f script.awk -arg
mawk: not an option -arg
$ gawk -f script.awk -arg
ARGC 2
ARG0 gawk
ARG1 -arg
尽管如此,必须指出的是,对于gawk和mawk,当参数与awk的可选参数发生冲突时,可以观察到不同的行为。示例:
$ mawk -f script.awk -var # this fails as gawk expects -v ar=foo
mawk: improper assignment: -v ar
$ gawk -f script.awk -var # this fails as gawk expects -v ar=foo
gawk: `oo' argument to `-v' not in `var=value' form
$ gawk -f script.awk -var=1 # this works and creates variable ar
$ mawk -f script.awk -var=1 # this works and creates variable ar
$ mawk -f script.awk -foo # this fails as it expects a file oo
mawk: cannot open oo (No such file or directory)
$ gawk -f script.awk -foo # this fails as it expects a file oo
gawk: fatal: can't open source file `oo' for reading (No such file or directory)
观察2: OP建议使用双引号
--
:表示选项的明确结尾。 来源:man mawk
--
:表明选项已结束。这对于允许AWK程序本身的更多参数以-
开头很有用。这提供了与大多数其他POSIX程序使用的参数解析约定的一致性。 来源:man gawk
此外,双连字符的用法假定--
之后的所有参数都是文件:
$ ./script.awk -- -arg1 file
ARGC 3
ARG0 mawk
ARG1 -arg1
ARG2 file
mawk: cannot open -arg1 (No such file or directory)
建议1:尽管标志的概念很不错,但您可以考虑将标准POSIX compliant分配用作参数:
$ ./script.awk arg1=1 arg2=1 arg3=1 file
但是,这样做的缺点是仅在执行BEGIN
块之后才处理这些分配。 (POSIX standard)
建议2 :一个简单的改进是使用ARGV
和ARGC
并使用无连字符的参数。这有点像BSD(cfr ps aux
),看起来可能像这样:
$ ./script.awk arg1 arg2 arg3
ARGC 4
ARG0 gawk
ARG1 arg1
ARG2 arg2
ARG3 arg3
建议3:如果上述选项都不适合您,则必须考虑在sh
和awk
之间使用混合方式。混合一词表示我们编写了sh
和awk
都可以识别的语法。 awk程序由以下形式的对组成:
pattern { action }
其中pattern
可以忽略。这非常类似于sh
的复合命令语法:
{ compound-list ; }
这使我们现在可以编写以下shell脚本script.sh
:
#!/bin/sh
{ "awk" "-f" "$0" "--" "${@}" ; "exit" ;}
# your awk script comes here
通过这样编写,awk
会将第一个动作解释为字符串的串联。另一方面,sh
将按名义执行它。
可悲的是,尽管看起来很有希望,但由于双连字符的影响,不能起作用。
$ ./script.sh file # this works
ARGC 2
ARG0 awk
ARG1 file
$ ./script.sh -arg file # this does not work
ARGC 3
ARG0 mawk
ARG1 -arg1
ARG2 file
mawk: cannot open -arg1 (No such file or directory)
一个丑陋的解决方案可能是开始解析脚本本身,以删除前两行,然后再将其传递回awk。但这只会解决仅具有BEGIN块的脚本的问题。