shell - AWK 脚本 shebang 允许以破折号为前缀的参数

标签 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 到这种程度?主要是出于好奇,但也是为了摆脱包装 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:虽然目前还不清楚,但必须指出的是,错误消息是由 ma​​wk 生成的,而不是更常见的 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:一个简单的改进是利用 ARGVARGC并使用无连字符的参数。这有点像 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/

相关文章:

python - 如何在 Python 中只查找总 RAM

linux - 在 make 文件中正常分配和导出分配之间的区别

linux - shell 脚本 : replacing and adding characters in a string

linux - 如何在 shell 中打印单词 n 个单词?

linux - 每次系统启动时更改墙纸的 Shell 脚本

file - 如何在 Linux 上通过脚本找到文件的编码?

shell - 在 shell 脚本中调用 awk

bash - 在bash中使用awk计算sacct输出的列数

awk命令解析由新行分隔的文件

git - 用于检查当前 git 分支是否为 "x"的 bash 脚本