我想编写一个相当复杂的 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 到这种程度?主要是出于好奇,但也是为了摆脱包装 shell 脚本,我目前只能使用它来执行 AWK 脚本:
#!/bin/sh
awk -f script.awk -- "$@"
解决方案应该符合 POSIX 标准(假设 AWK 的路径为 /usr/bin/awk
)。即使您有不符合 POSIX 标准的解决方案,也请分享。
最佳答案
理解问题:
据我了解,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 风格的长选项来调用它。 POSIX 选项以单个 -
) 开头,而长选项以两个 --
) 开头。然而,这会失败,因为 awk 正在将这些参数解释为传递给 awk 本身,而不是传递给脚本参数列表。例如。
$ ./script.awk
ARGC 1
ARG0 awk
$ ./script.awk -arg
awk: not an option: -arg
Question: Is there a way to write a POSIX compliant script which can handle such hyphenated arguments? (Suggestions are made in the original question.)
观察 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建议使用双<连字符>来指示连续选项只是awk的一部分。然而,这是 mawk 和 gawk 的扩展,而不是 POSIX standard 的一部分。 .
--
: indicates the unambiguous end of options. source:man mawk
--
: Signal the end of options. This is useful to allow further arguments to the AWK program itself to start with a-
. This provides consistency with the argument parsing convention used by most other POSIX programs. source: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
之后处理。 block 被执行。 (参见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 block 的脚本的问题。
关于shell - AWK 脚本 shebang 允许以破折号为前缀的参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55264872/