Shell AWK脚本shebang允许带破折号前缀的参数

Shell AWK脚本shebang允许带破折号前缀的参数,shell,awk,sh,posix,Shell,Awk,Sh,Posix,我想编写一个相当复杂的AWK脚本,它将接受一组命令行参数,解析它们,然后执行一些工作 不幸的是,我在尝试将带破折号前缀(-arg)的参数传递给脚本时遇到了麻烦,因为它们是由AWK解释的 $ ./script.awk -arg awk: not an option: -arg 我注意到了--选项,但我不确定如何在shebang中有意义地使用它。我无法找到任何方法获取文件名并在脚本的shebang中引用它(类似于#!/usr/bin/awk-f$file--) 然后我想也许可以使用-W exec选

我想编写一个相当复杂的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脚本:

#/垃圾箱/垃圾箱
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]}
问题:有没有办法编写一个兼容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的一个扩展,而不是

--
:表示选项的明确结束来源:
manmawk

--
:表示选项结束。这对于允许AWK程序本身的进一步参数以
-
开头非常有用。这提供了与大多数其他POSIX程序使用的参数解析约定的一致性来源:
人呆呆地看

此外,双连字符的使用假定
--
之后的所有参数都是文件:

$ ./script.awk -- -arg1 file
ARGC 3
ARG0 mawk
ARG1 -arg1
ARG2 file
mawk: cannot open -arg1 (No such file or directory)

<强>建议1:当标志的概念很好时,可以考虑使用标准赋值作为参数:

$ ./script.awk arg1=1 arg2=1 arg3=1 file
但是,这样做的缺点是,只有在执行
BEGIN
块之后,才会处理这些分配。(美国联邦法规)

建议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 之间使用混合。单词hybrid意味着我们编写的语法是由

sh
awk
识别的。awk程序由以下形式的成对程序组成:

pattern { action }
其中,
模式
可以忽略。这与
sh
的复合命令语法非常相似:

{ compound-list ; }
#!/bin/sh
{ "awk" "-f" "$0" "--" "${@}" ; "exit" ;}
# your awk script comes here
这允许我们现在编写以下shell脚本
script.sh

{ compound-list ; }
#!/bin/sh
{ "awk" "-f" "$0" "--" "${@}" ; "exit" ;}
# your awk script comes here
通过这样编写,
awk
将第一个操作解释为字符串的串联<另一方面,code>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块的脚本的问题。

如果没有shell脚本包装,可能不可能。阅读你的
execve(2)
manpage@glennjackman这是我一开始的想法,但后来我想起,shell/-nix中的所有东西都有一个典型的黑客解决方案。谢天谢地,似乎确实有一种方法可以实现这一点(见下文)。如果你创建了一个新的应用程序,我们可以向你展示如何最好地实现它。@EdMorton我不太确定你在这种情况下的意思。我已经给出了一个例子,说明了传递给脚本的参数可能是什么样子的,但其余的只是一个通用的AWK脚本(其中大部分还没有编写,因为这是我开始处理的第一个问题之一)。我需要所有标准的AWK功能。我不认为如果你的shell脚本是
#下200行AWK代码会有什么不同/bin/awk
shebang或200行awk包装在
awk'…'
中。这两种方式都是相同的200行awk代码。对我来说,这个解决方案在脚本执行结束时打印
Hangup
(可能是WSL Debian的
sh
报告SIGHUP的怪癖)。在我看来,将
kill
命令替换为普通的
exit
解决了这个问题。我错过什么了吗?另外,我相信您省略了dash前缀参数工作所需的关键部分(除非我弄错了,否则AWK调用应该是
AWK-f“$0”“--”$@
)。