【问题标题】:Understanding the awk -f option in shebang line了解 shebang 行中的 awk -f 选项
【发布时间】:2015-11-30 22:27:03
【问题描述】:

我正在阅读某人的 awk 脚本。以标题 #!/usr/bin/env awk -f 开头。 env 命令没有-f 选项。因此,他们必须为 awk 命令传递 -f 选项。我查看了 awk 的手册页。它说 Awk 扫描每个输入文件以查找与 prog 或一个或多个指定为 -f progfile 的文件中指定的一组模式中的任何一个匹配的行。对于每个模式,当文件的一行与模式匹配时,将执行一个关联的操作。

根据我的理解,这意味着 awk 通过搜索具有在 progfile/prog 中指定的模式的行来处理输入文件,具体取决于您是否将 -f 选项与 awk 一起使用。并根据使用的模式,对输入文件中的行执行相关操作。我的问题是......在运行 awk 脚本文件时这是如何工作的?我们没有在#!/usr/bin/env awk -f 行中指定 progfile。 awk 脚本将使用哪些模式?或者这是否意味着我们必须在运行 awk 脚本时传递 progfile?如果是这种情况,在脚本中指定 -f 选项不是多余的吗?如果我们不指定progfile,会默认忽略-f选项还是抛出错误?

为了更好地理解这一点,我编写了一个简单的 awk 脚本并将其保存为 test.awk

#!/usr/bin/env awk -f

BEGIN { print "START" }

当我运行它时,字符串“START”会打印在屏幕上。

prachis-mbp-2:~ pskhadke$ ./test.awk
START

如果我从 awk 脚本的第一行删除 -f 选项并运行它,我会收到以下错误:

prachis-mbp-2:~ pskhadke$./test.awk
awk: syntax error at source line 1
 context is
     >>> . <<< /test.awk

同样,

prachis-mbp-2:~ pskhadke$ awk test.awk
awk: syntax error at source line 1
 context is
     >>> test. <<< awk
awk: bailing out at source line 1

因此,由于某种原因,如果没有 -f 选项,它就无法正确解析参数。但是为什么呢?

【问题讨论】:

    标签: linux awk


    【解决方案1】:

    文件名附加到命令末尾的 shebang 行中。因此,为标题为#!/usr/bin/env awk -f 的文件test.awk 有效执行的生成命令行将是awk -f test.awk,将test.awk 视为要执行的脚本文件而不是数据输入文件。

    最好的例子:创建一个文件test,作为唯一内容#!/bin/rm,使其可执行(例如chmod 755)并尝试通过运行./test来执行它。现在,那个文件去哪儿了:)

    【讨论】:

    • 即使其他答案是正确的,也接受了你的答案,因为你解释了我们需要 -f 的主要原因。我不知道脚本名称会附加在awk -f 的末尾。赞成所有正确的答案。
    • 我还没有阅读其余的答案,但希望有人指出你不应该通过 shebang 调用 awk。
    • 不,没有人指出永远不应该通过 shebang 调用 awk。你能解释一下原因吗?
    • @JamesBrown 因为与简单地从 shell 脚本调用 awk 相比,它没有任何有用的优势,而它的显着缺点是不能将 shell 脚本 args 分成 shell args、awk args 和 awk 变量设置。参见例如unix.stackexchange.com/a/563456/133219
    • @Prachi 抱歉,我在 4 年前没有看到上面的 your commentI responded now FWIW :-)。
    【解决方案2】:

    因此,他们必须为 awk 命令传递 -f 选项。

    是的,没错。 shebang 行在调用时由内核解释。如果它读取#!/usr/bin/env awk -f,则意味着当此文件作为可执行文件调用时(即,当它作为程序参数传递给七个exec 函数之一时),“执行”它的正确方法是通过执行awk -f &lt;filename&gt;。换句话说:exec 函数将使用正确的参数调用解释器,而不是尝试执行文件本身(因为它不是二进制文件)。

    -f 选项是必需的,因为awk(1) 默认从参数中读取程序;如果你想让它从文件中读取它,你需要-f

    据我了解,这意味着 awk 处理输入 文件通过搜索具有指定模式的行 progfile/prog 取决于您是否在 awk 中使用 -f 选项。

    awk(1) 始终处理输入文件以查找匹配项。 -f 选项仅控制从何处读取 awk 程序。如果启用,则意味着第一个文件名实际上是包含 awk 程序的文件名。否则,第一个文件名是开始寻找模式的第一个文件。如果未指定文件,则仅匹配 stdin 中的行。

    我们没有在 #!/usr/bin/env awk -f 行中指定 progfile

    内核会为你做这件事。再次,shebang 行说:当你想执行这个文件时(叫它X),那么请用awk -f 执行。所以相当于awk -f X

    如果我从 awk 脚本的第一行删除 -f 选项并运行它,我会收到以下错误:

    因为那将与以下内容相同:

    $ awk ./test.awk
    

    这是废话,因为没有-f,它会尝试将./test.awk解释为awk程序。所以你得到一个错误。

    【讨论】:

    • 请注意谁编辑了我的答案,以及同意编辑的批准者:读取和解释 shebang 行的是内核。另外,请不要通过删除反引号并将其替换为 ' 来取消我的帖子格式。
    • 是的,对不起 - 我困了,我把它弄碎了,然后我完全忘了回来收回它。
    【解决方案3】:
    #!/usr/bin/env awk -f
    

    #! 后面的字符串在附加脚本名称后作为命令调用。

    如果您阅读env 命令的文档,您会看到(在没有任何NAME=VALUE 或其他选项的情况下)它调用它的第一个参数作为命令,将任何后续参数传递给该命令。所以env 会调用awk -f name-of-script

    您需要-f 的原因仅仅是因为awk 就是这样处理它的命令行参数的。如果您在 awk 的命令行上传递一个字符串而不指定选项名称,它将将该字符串评估为 awk 代码:

    $ awk 'BEGIN {print "hello, world"}'
    hello, world
    

    要告诉awk 执行文件的内容,您必须使用-f 选项:

    $ echo 'BEGIN { print "hello, world"}' > hello.awk
    $ awk -f hello.awk
    hello, world
    

    与大多数其他解释器相比,这实际上有点不寻常。例如,perl 命令默认将命令行参数视为脚本名称;要在命令行上传递 Perl 代码,您必须使用 -e 选项:

    $ perl -e 'print "hello, world\n"'
    hello, world
    

    大多数外壳都是一样的。

    请注意,一些较旧的系统会限制您在 #! 行上可以拥有的参数数量,因此 #!/usr/bin/env awk -f 可能无法使用。

    如果你知道awk解释器命令的确切位置,你可以直接使用它而不是使用/usr/bin/env

    #!/usr/bin/awk -f
    

    请参阅 this questionmy answer,了解有关 #!/usr/bin/env hack 的讨论。

    【讨论】:

      【解决方案4】:

      Shebang 行将由内核解释,内核将调用 shebang 之后指定的解释器,并以可执行文件名(您的脚本)作为参数。参见man 2 execve,“解释器脚本”部分

      【讨论】:

        猜你喜欢
        • 2013-12-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-05
        • 2011-03-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多