如何使用shebang(即#!)为awk使用多个参数?

时间:2010-11-29 11:04:22

标签: shell unix awk gawk shebang

我想使用shebang与--re-interval执行gawk脚本。

的“幼稚”方法
#!/usr/bin/gawk --re-interval -f
... awk script goes here

不起作用,因为使用第一个参数"--re-interval -f"调用gawk(不是在空白处分开),这是不明白的。是否有解决方法?

当然你可以不直接调用gawk,而是将它包装成一个分割第一个参数的shell脚本,或者创建一个shell脚本然后调用gawk并将脚本放到另一个文件中,但我想知道是否有一些在一个文件中执行此操作的方法。

shebang行的行为因系统而异 - 至少在Cygwin中它不会通过空格分割参数。我只关心如何在一个行为类似的系统上做到这一点;该脚本不是便携式的。

10 个答案:

答案 0 :(得分:150)

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

对它的作用有一个粗略的共识:在!\n以及exec之间取一切。假设!\n之间的所有内容都是解释器的完整绝对路径。如果它包含空格,则没有达成共识。

  1. 有些操作系统只是将整个事物视为路径。毕竟,在大多数操作系统中,空格或破折号在路径中是合法的。
  2. 某些操作系统在空白处拆分,并将第一部分视为解释器的路径,其余部分视为单独的参数。
  3. 某些操作系统在第一个空白处拆分,并将前端部分视为interpeter的路径,将其余部分视为单个参数(这是您所看到的) )。
  4. 有些人甚至根本不支持shebang line
  5. 值得庆幸的是,1。和4.似乎已经消亡,但是3.非常普遍,所以你根本不能依赖能够传递多个参数。

    由于命令的位置也未在POSIX或SUS中指定,因此通常会将可执行文件的名称传递给env,以便 it < / em>可以确定可执行文件的位置; e.g:

    #!/usr/bin/env gawk
    

    [显然,这个仍然假设env的特定路径,但它只有很少的系统存在于/bin中,所以这通常是安全的。 env的位置比gawk的位置更加标准化,甚至比pythonrubyspidermonkey更糟糕。]

    这意味着您无法实际使用任何参数

答案 1 :(得分:22)

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

#!/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

答案 2 :(得分:11)

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

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

例如,你不能拥有

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

但你可以

#!/usr/bin/foo -if

显然,只有在选项具有短等价物且不带参数时才有效。

答案 3 :(得分:11)

在Cygwin和Linux下,shebang路径之后的一切都被解析为程序作为一个参数。

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

#!/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

答案 4 :(得分:5)

#!/bin/sh
''':'
exec YourProg -some_options "$0" "$@"
'''

上面的shell shebang技巧比/usr/bin/env更便携。

答案 5 :(得分:5)

尽管不是完全可移植的,但从coreutils 8.30和according to its documentation开始,您将能够使用:

#!/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

原始答案here

答案 6 :(得分:3)

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

答案 7 :(得分:3)

为什么不使用bashgawk本身,跳过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
}

( - 自然也可以用sedtail来完成,但我认为只有bashgawk本身才会有某种美; )

答案 8 :(得分:0)

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

#!/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在脚本上进行了变量扩展,所以你必须引用每个$(如脚本的第二行所做的那样)并且可能更多。

答案 9 :(得分:-1)

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

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

注意: -f没有awk个参数。这使得stdin可以awk从中读取输入。假设你已经gawk安装了PATH,那就完成了我认为你试图用你的原始例子做的一切(假设你想要文件内容是awk脚本而不是输入,我认为你的shebang方法会把它视为。)。