我想使用shebang用--re-interval执行一个gawk脚本。"幼稚"的方法
1 2
| #!/usr/bin/gawk --re-interval -f
... awk script goes here |
不起作用,因为gawk是用第一个参数"--re-interval -f"(不是在空白处分开)调用的,它不明白。 有解决方法吗?
当然你可以不直接调用gawk,而是将它包装成一个分割第一个参数的shell脚本,或者创建一个shell脚本,然后调用gawk并将脚本放到另一个文件中,但我想知道是否有某种方法可以做 这在一个文件中。
shebang行的行为因系统而异 - 至少在Cygwin中它不会通过空格分割参数。 我只关心如何在一个行为类似的系统上做到这一点; 该脚本不是便携式的。
-
我刚刚做的一个愚蠢的实验是使用一个脚本在shebang线上使用另一个脚本,它确实正确地分割了参数。
-
@Hasturkun提出了另一个问题,即shebang行的行为也因系统而异,wrt被调用的程序本身是否可以是脚本。
-
stackoverflow.com/questions/17458528/why-does-this-snippet-work
-
使用最新版本的gawk(> = 4.0),不再需要--re-interval(参见[gnu.org/software/gawk/manual/)。
shebang系列从未被指定为POSIX,SUS,LSB或任何其他规范的一部分。 AFAIK,它甚至没有被正确记录。
关于它的作用有一个大致的共识:在!和
以及exec之间取得一切。假设!和
之间的所有内容都是解释器的完整绝对路径。如果它包含空格,则没有达成共识。
有些操作系统只是将整个事物视为路径。毕竟,在大多数操作系统中,空格或破折号在路径中是合法的。
某些操作系统在空白处拆分,并将第一部分视为解释器的路径,其余部分作为单独的参数。
某些操作系统在第一个空格处分开,并将前部分视为interpeter的路径,将其余部分视为单个参数(这是您所看到的)。
有些甚至根本不支持shebang线。
值得庆幸的是,1.和4.似乎已经消亡,但是3.相当普遍,所以你根本不能依靠能够传递多个参数。
由于命令的位置也没有在POSIX或SUS中指定,因此通常会通过将可执行文件的名称传递给env来使用该单个参数,以便它可以确定可执行文件的位置;例如。:
[显然,这仍然假定env的特定路径,但是它只有很少的系统存在于/bin中,所以这通常是安全的。 env的位置比gawk的位置更加标准化,甚至更糟糕的是python或ruby或spidermonkey。
这意味着您根本无法使用任何参数。
-
非常感谢您的深刻见解!但在这种情况下,我不关心可移植性,所以我澄清了我的问题。
-
FreeBSD的env??有一个-S开关,在这里有帮助,但它不存在于我的Linux env上,我怀疑在gygwin上也没有。 @hstoerr,其他具有不同情况的用户可能会在以后阅读您的问题,因此通常便携式答案更可取,即使您现在不需要可移植性。
-
所以我们不能在shebang中使用参数。但是如果我们需要通过任何必要的方式进行论证呢我猜测解决方案是编写一个包含#!/bin/sh和/usr/bin/env gawk --re-interval -f my-script.awk的包装器shell脚本。那是对的吗?
-
听起来像-S选项对于添加到env的GNU coreutils版本会有用吗?和/或linux内核shebang行为被修改为类似于选项2 ...虽然我认为后者的变化会存在兼容性问题。
-
我不同意。你可以很方便地使用一个参数。任何你不能使用任何参数的系统都无法实现这种传统的Unix主义,这就是hash-bang。如果非实现是公平游戏,那么我们可以有把握地说#!本身不可移植。例如,Windows根本不会"本机地"识别此约定。传统上,Unix上需要一个单一的参数才能做#!/usr/bin/awk -f。
-
@Kaz:是的,但是由于许多二进制文件的路径没有标准化,所以你会用掉#!/usr/bin/env ruby或类似的一个参数。
-
为了完整起见,我想补充一下这句话:如果shebang行是#!/bin/bash -ex,则相当于执行/bin/bash -ex /path/too/foo arg1 arg2。此功能由内核管理。
-
@JrgWMittag,你的最后一段,那么解决方案是什么?
-
@Pacerier:更改POSIX规范并等待20 - 30年,直到所有系统都更新为符合规范。
这似乎对我有用(g)awk。
1 2 3 4 5 6
| #!/bin/sh
arbitrary_long_name==0"exec""/usr/bin/gawk""--re-interval""-f""$0""$@"
# The real awk program starts here
{ print $0 } |
请注意#!运行/bin/sh,因此该脚本首先被解释为shell脚本。
起初,我只是尝试"exec""/usr/bin/gawk""--re-interval""-f""$0""$@",但是awk将其视为一个命令并无条件地打印出每一行输入。这就是我放入arbitrary_long_name==0的原因 - 它应该一直都会失败。你可以用一些乱码的字符串替换它。基本上,我在awk中寻找一个不会对shell脚本产生负面影响的错误条件。
在shell脚本中,arbitrary_long_name==0定义了一个名为arbitrary_long_name的变量,并将其设置为=0。
-
这是我的答案,但我想知道它是否足够便携和强大。它是否特别依赖于bash,还是适用于任何POSIX sh?而且我不经常使用awk,所以我不确定我在第二行的技巧是强制awk忽略该行的好方法。
-
正是我想知道的是+1,但可能是不可取的(因此相对投票)。
-
你能解释一下这可能有什么问题吗,@ AaronHall?只要变量arbitrary_long_name不与真正的awk程序中使用的变量冲突,我就看不到任何问题。有什么我想念的吗?
在Cygwin和Linux下,shebang路径之后的所有内容都被解析为程序作为一个参数。
通过在shebang中使用另一个awk脚本可以解决这个问题:
1
| #!/usr/bin/gawk {system("/usr/bin/gawk --re-interval -f" FILENAME); exit} |
这将在awk中执行{system("/usr/bin/gawk --re-interval -f" FILENAME); exit}。
这将在您的系统shell中执行/usr/bin/gawk --re-interval -f path/to/your/script.awk。
我遇到了同样的问题,没有明显的解决方案,因为在shebang处理空白的方式(至少在Linux上)。
但是,你可以在shebang中传递几个选项,只要它们是短选项并且它们可以连接(GNU方式)。
例如,你不能拥有
但你可以拥有
显然,只有在选项具有短等价物且不带参数时才有效。
尽管不是完全可移植的,但从coreutils 8.30开始,根据其文档,您将能够使用:
1
| #!/usr/bin/env -S command arg1 arg2 ... |
所以给出:
1 2
| $ cat test.sh
#!/usr/bin/env -S showargs here 'is another' long arg -e"this and that" too |
你会得到:
1 2 3 4 5 6 7 8 9 10
| % ./test.sh
$0 is '/usr/local/bin/showargs'
$1 is 'here'
$2 is 'is another'
$3 is 'long'
$4 is 'arg'
$5 is '-e'
$6 is 'this and that '
$7 is 'too'
$8 is './test.sh' |
如果你好奇showargs是:
1 2 3 4 5 6 7 8
| #!/usr/bin/env sh
echo"\$0 is '$0'"
i=1
for arg in"$@"; do
echo"\$$i is '$arg'"
i=$((i+1))
done |
原来答案在这里。
-
仅供参考,FreeBSD已经-S多年(自6.0起)。 这是coreutils的一个受欢迎的可移植性补充。
1 2 3 4
| #!/bin/sh
''':'
exec YourProg -some_options"$0""$@"
''' |
上面的shell shebang技巧比/usr/bin/env更便携。
-
'''''是一个保留,因为我的原始解决方案是用于python脚本,所以''':'告诉python解释器忽略exec部分。
-
我认为你被低估了,因为你的解决方案是python,但这个问题是关于awk。
-
伟大的黑客Python。
-
天才!谢谢哥们儿。
为什么不使用bash和gawk本身,跳过shebang,阅读脚本,并将其作为文件传递给gawk [--with-whatever-number-of-params-you-need]的第二个实例?
1 2 3 4 5 6 7
| #!/bin/bash
gawk --re-interval -f <(gawk 'NR>3' $0 )
exit
{
print"Program body goes here"
print $1
} |
( - 自然也可以用例如sed或tail完成,但我认为只有bash和gawk本身才会有某种美;)
在gawk手册(http://www.gnu.org/manual/gawk/gawk.html)中,1.14节的末尾注意到从shebang行运行gawk时应该只使用一个参数。它说操作系统会将通往gawk的路径之后的所有内容视为一个参数。也许有另一种方法来指定--re-interval选项?也许你的脚本可以在shebang行中引用你的shell,运行gawk作为命令,并将脚本的文本包含为"here document"。
-
似乎没有其他方法可以指定该选项。你是对的:gawk -f - << EOF,一些脚本行,EOF工作,但它阻止我用gawk阅读标准输入。
-
这里的文档占用了gawk的标准输入流,但你仍然可以通过stderr管道输入(也就是说,在管道进入这个脚本之前将stdout重定向到stderr)。我从来没有尝试过,但只要第一个进程在stderr上没有发出任何东西,它就可以工作了。如果要确保没有其他任何东西正在使用它,您还可以创建命名管道(linuxjournal.com/content/using-named-pipes-fifos-bash)。
只是为了好玩:有以下非常奇怪的解决方案,通过文件描述符3和4重新路由stdin和程序。您还可以为脚本创建一个临时文件。
1 2 3 4 5 6 7
| #!/bin/bash
exec 3>&0
exec <<-EOF 4>&0
BEGIN {print"HALLO"}
{print \$1}
EOF
gawk --re-interval -f <(cat 0>&4) 0>&3 |
有一点令人讨厌:shell在脚本上进行了可变扩展,所以你必须引用每个$(如脚本的第二行所做的那样),可能还要多。
对于可移植的解决方案,使用awk而不是gawk,使用shebang调用标准BOURNE shell(/bin/sh),并直接调用awk,将命令行上的程序作为here文档传递,而不是通过标准输入:
1 2 3 4
| #!/bin/sh
gawk --re-interval <<<EOF
PROGRAM HERE
EOF |
注意:awk没有-f参数。这使stdin的stdin可用于读取输入。假设您已经安装gawk并且在PATH上,这实现了我认为您尝试使用原始示例的所有内容(假设您希望文件内容是awk脚本而不是输入,我认为您的shebang方法会把它当作)。
-
这对我不起作用。 bash男人说<<< blabla把blabla放在stdin身上。你的意思是<< - EOF?无论哪种方式,这也将程序放在stdin上。