Shell 如何对带有shebang(即#!)的awk使用多个参数?

Shell 如何对带有shebang(即#!)的awk使用多个参数?,shell,unix,awk,gawk,shebang,Shell,Unix,Awk,Gawk,Shebang,我想使用shebang执行带有--re interval的脚本。教育的“幼稚”方法 #!/usr/bin/gawk --re-interval -f ... awk script goes here 不起作用,因为gawk是用第一个参数--re interval-f调用的,它不理解。有解决办法吗 当然,您可以不直接调用gawk,而是将其包装到拆分第一个参数的shell脚本中,或者制作一个shell脚本,然后调用gawk并将脚本放入另一个文件中,但我想知道是否有某种方法可以在一个文件中实现这一点

我想使用shebang执行带有
--re interval
的脚本。教育的“幼稚”方法

#!/usr/bin/gawk --re-interval -f
... awk script goes here
不起作用,因为gawk是用第一个参数--re interval-f调用的,它不理解。有解决办法吗

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


shebang行的行为因系统而异——至少在这一点上,它不会用空格分隔参数。我只关心如何在这样一个系统上实现它;该脚本不可移植。

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

shebang行从未被指定为POSIX、SUS、LSB或任何其他规范的一部分。抱歉,它甚至还没有被正确地记录下来

关于它的作用有一个大致的共识:在<代码>之间获取一切和
\n
exec
执行它。假设
之间的所有内容
\n
是解释器的完整绝对路径。对于包含空格的情况下会发生什么,目前还没有达成共识

  • 有些操作系统只是将整个过程视为路径。毕竟,在大多数操作系统中,空格或破折号在路径中是合法的
  • 一些操作系统以空格分隔,并将第一部分视为通往解释器的路径,其余部分视为单独的参数
  • 一些操作系统在第一个空格处拆分,并将前面的部分视为指向interpeter的路径,其余部分视为单个参数(这就是您所看到的)
  • 有些甚至根本不支持shebang线路
  • 谢天谢地,1。四,。似乎已经消失了,但是3。是相当普遍的,所以你不能仅仅依靠能够通过一个以上的论点

    由于命令的位置在POSIX或SUS中也没有指定,因此通常通过将可执行文件的名称传递给
    env
    来使用单个参数,以便它可以确定可执行文件的位置;e、 g:

    #!/usr/bin/env gawk
    
    [显然,这仍然假定
    env
    有一个特定的路径,但它位于
    /bin
    中的系统很少,因此这通常是安全的。
    env
    的位置比
    gawk
    的位置标准化得多,甚至比
    python
    ruby
    spidermonkey
    ]


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

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

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

    例如,你不能有

    #!/usr/bin/foo -i -f
    
    但是你可以

    #!/usr/bin/foo -if
    

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

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

    #!/bin/sh
    gawk --re-interval <<<EOF
    PROGRAM HERE
    EOF
    
    !/bin/sh
    
    gawk--re interval只是为了好玩:有一个非常奇怪的解决方案,它通过文件描述符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
    
    !/bin/bash
    执行3>&0
    行政及3
    
    有一件事让人恼火:shell对脚本进行变量扩展,因此您必须引用每一个$(如脚本第二行中所做的),而且可能还要引用更多

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

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

    更具可移植性,这似乎适用于(g)awk

    请注意,
    #!
    运行
    /bin/sh
    ,因此此脚本首先被解释为shell脚本

    起初,我只是简单地尝试了
    “exec”“/usr/bin/gawk”“--re interval”“-f”“$0”“$@”
    ,但awk将其视为一个命令,并无条件地打印出每一行输入。这就是为什么我输入了
    任意的\u long\u name==0
    -它应该一直失败。你可以用一些乱七八糟的字符串替换它。基本上,我在awk中寻找一个不会对shell脚本产生不利影响的错误条件


    在shell脚本中,
    arbitral_long_name==0
    定义了一个名为
    arbitral_long_name
    的变量,并将其设置为Cygwin和Linux下的
    =0
    ,将shebang的路径作为一个参数解析到程序后的所有内容

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

    #!/usr/bin/gawk {system("/usr/bin/gawk --re-interval -f " FILENAME); exit}
    
    这将在awk中执行
    {system(“/usr/bin/gawk--re interval-f”文件名);退出}


    这将在您的系统shell中执行
    /usr/bin/gawk--re interval-f path/to/your/script.awk

    为什么不使用
    bash
    gawk
    本身,跳过shebang,读取脚本,并将其作为文件传递给
    gawk[--使用您需要的任何数量的参数]

    #!/bin/bash
    gawk --re-interval -f <(gawk 'NR>3' $0 )
    exit
    {
      print "Program body goes here"
      print $1
    }
    
    !/bin/bash
    gawk--re间期-f虽然不是e
    
    #!/bin/bash
    gawk --re-interval -f <(gawk 'NR>3' $0 )
    exit
    {
      print "Program body goes here"
      print $1
    }
    
    #!/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'
    
    #!/usr/bin/env sh
    echo "\$0 is '$0'"
    
    i=1
    for arg in "$@"; do
        echo "\$$i is '$arg'"
        i=$((i+1))
    done