128

我想使用 shebang执行一个gawk脚本。--re-interval“天真”的做法

#!/usr/bin/gawk --re-interval -f
... awk script goes here

不起作用,因为 gawk 是用第一个参数调用的"--re-interval -f"(没有在空格周围分割),它不理解。有解决方法吗?

当然,您可以不直接调用 gawk 而是将其包装到拆分第一个参数的 shell 脚本中,或者制作一个 shell 脚本,然后调用 gawk 并将脚本放入另一个文件中,但我想知道是否有办法做这在一个文件中。

shebang 行的行为因系统而异——至少在Cygwin中,它不会用空格分割参数。我只关心如何在这样的系统上执行此操作;该脚本并不意味着可移植。

4

10 回答 10

162

shebang 线从未被指定为 POSIX、SUS、LSB 或任何其他规范的一部分。AFAIK,它甚至没有被正确记录。

关于它的作用有一个粗略的共识:获取和它之间的!所有\n内容exec!假设是和之间的一切都是\n解释器的完整绝对路径。如果它包含空格会发生什么,没有共识。

  1. 一些操作系统只是将整个事物视为路径。毕竟,在大多数操作系统中,空格或破折号在路径中是合法的。
  2. 一些操作系统在空白处拆分并将第一部分视为解释器的路径,其余部分视为单独的参数。
  3. 一些操作系统在第一个空格处拆分,并将前面部分视为通向 interpeter 的路径,其余部分视为单个参数(这就是您所看到的)。
  4. 有些甚至根本不支持shebang线。

值得庆幸的是,1. 和 4. 似乎已经消失了,但 3. 相当普遍,所以你不能指望能够传递多个参数。

而且由于在 POSIX 或 SUS 中也没有指定命令的位置,因此您通常通过传递可执行文件的名称来使用该单个参数,env以便可以确定可执行文件的位置;例如:

#!/usr/bin/env gawk

[显然,这仍然假设 的特定路径env,但它所在的系统很少/bin,因此这通常是安全的。的位置比or或env的位置更标准化,gawk甚至更糟。]pythonrubyspidermonkey

这意味着您实际上根本无法使用任何参数。

于 2010-11-29T13:26:53.250 回答
37

虽然不完全可移植,但从 coreutils 8.30 开始,根据其文档,您将能够使用:

#!/usr/bin/env -S command arg1 arg2 ...

所以给出:

$ cat test.sh
#!/usr/bin/env -S showargs here 'is another' long arg -e "this and that " too

你会得到:

% ./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是:

#!/usr/bin/env sh
echo "\$0 is '$0'"

i=1
for arg in "$@"; do
    echo "\$$i is '$arg'"
    i=$((i+1))
done

原始答案在这里

于 2018-10-25T01:12:30.353 回答
27

这似乎对我有用(g)awk。

#!/bin/sh
arbitrary_long_name==0 "exec" "/usr/bin/gawk" "--re-interval" "-f" "$0" "$@"


# The real awk program starts here
{ print $0 }

注意#!runs /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.

于 2014-09-26T09:48:27.157 回答
13

我遇到了同样的问题,由于在 shebang 中处理空格的方式(至少在 Linux 上),没有明显的解决方案。

但是,您可以在 shebang 中传递多个选项,只要它们是短选项并且可以连接(GNU 方式)。

例如,您不能拥有

#!/usr/bin/foo -i -f

但你可以拥有

#!/usr/bin/foo -if

显然,这仅在选项具有短等效项且不带参数时才有效。

于 2011-02-10T11:53:43.580 回答
11

在 Cygwin 和 Linux 下,shebang 路径之后的所有内容都作为一个参数解析到程序中。

awk可以通过在 shebang中使用另一个脚本来解决这个问题:

#!/usr/bin/gawk {system("/usr/bin/gawk --re-interval -f " FILENAME); exit}

这将{system("/usr/bin/gawk --re-interval -f " FILENAME); exit}在 awk 中执行。
这将/usr/bin/gawk --re-interval -f path/to/your/script.awk在您的系统外壳中执行。

于 2016-04-12T20:03:10.047 回答
4
#!/bin/sh
''':'
exec YourProg -some_options "$0" "$@"
'''

上面的 shell shebang 技巧比/usr/bin/env.

于 2014-01-10T19:11:37.700 回答
3

在 gawk 手册 (http://www.gnu.org/manual/gawk/gawk.html) 中,第 1.14 节的末尾请注意,当从 shebang 行运行 gawk 时,您应该只使用单个参数。它表示操作系统会将 gawk 路径之后的所有内容视为单个参数。也许还有另一种指定--re-interval选项的方法?也许您的脚本可以在 shebang 行中引用您的 shell,gawk作为命令运行,并将您的脚本文本作为“此处文档”包含在内。

于 2010-11-29T12:59:14.430 回答
3

为什么不使用bashandgawk本身,跳过 shebang,阅读脚本,并将其作为文件传递给gawk [--with-whatever-number-of-params-you-need]?

#!/bin/bash
gawk --re-interval -f <(gawk 'NR>3' $0 )
exit
{
  print "Program body goes here"
  print $1
}

(- 自然也可以使用 eg sedor来实现tail,但我认为有某种美仅取决于bashandgawk本身;)

于 2017-09-13T09:55:40.380 回答
0

只是为了好玩:有以下非常奇怪的解决方案,通过文件描述符 3 和 4 重新路由标准输入和程序。您还可以为脚本创建一个临时文件。

#!/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 在脚本上进行变量扩展,所以你必须引用每个 $(就像在脚本的第二行中所做的那样),而且可能不止于此。

于 2013-03-15T13:50:24.213 回答
-1

对于可移植的解决方案,使用awk而不是,用你的 shebanggawk调用标准的 BOURNE shell ( ),然后直接调用,在命令行上将程序作为 here 文档而不是通过 stdin 传递:/bin/shawk

#!/bin/sh
gawk --re-interval <<<EOF
PROGRAM HERE
EOF

注意:没有-f参数awk. 这留下stdin了可供awk读取的输入。假设您已经gawk安装并在您的 上PATH,这实现了我认为您尝试对原始示例执行的所有操作(假设您希望文件内容是 awk 脚本而不是输入,我认为您的 shebang 方法会将其视为)。

于 2013-03-13T21:06:19.863 回答