AWK脚本shebang允许使用短划线前缀的参数

时间:2019-03-20 15:46:39

标签: shell awk sh posix

我想编写一个相当复杂的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的解决方案,也请共享它。

1 个答案:

答案 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建议使用双引号来表示连续的选项只是awk的一部分。但是,这是mawk和gawk的扩展,而不是POSIX standard的一部分。

  

-- :表示选项的明确结尾。 来源: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 :一个简单的改进是使用ARGVARGC并使用无连字符的参数。这有点像BSD(cfr ps aux),看起来可能像这样:

$ ./script.awk arg1 arg2 arg3
ARGC 4
ARG0 gawk
ARG1 arg1
ARG2 arg2
ARG3 arg3

建议3:如果上述选项都不适合您,则必须考虑在shawk之间使用混合方式。混合一词表示我们编写了shawk都可以识别的语法。 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块的脚本的问题。