了解问题:
据我了解,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
问题:有没有办法编写一个符合 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: 一个简单的改进是使用 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 块的脚本的问题。