我正在阅读某人的awk脚本。从标题#!/usr/bin/env awk -f
开始。 env命令没有-f
选项。因此,他们必须传递awk命令的-f
选项。我查看了awk的手册页。它表示 Awk扫描每个输入文件,查找与prog中指定的任何一组模式匹配的行,或者指定为-f progfile的一个或多个文件中的任何模式。对于每个模式,当文件的一行与模式匹配时,可以执行相关的操作。
根据我的理解,这意味着awk通过搜索progfile / prog中指定模式的行来处理输入文件,具体取决于你是否在awk中使用-f选项。并且基于所使用的模式,对输入文件中找到的行执行相关动作。我的问题是......运行awk脚本文件时这是如何工作的?我们没有在#!/usr/bin/env awk -f
行中指定prog文件。 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
选项,它无法正确解析参数。但为什么呢?
答案 0 :(得分:3)
文件的名称将附加到shebang行中命令的末尾。因此,对于具有标头test.awk
的文件#!/usr/bin/env awk -f
有效执行的结果命令行将是awk -f test.awk
,将test.awk
视为要执行的脚本文件而不是数据输入文件。
最佳插图:使用唯一内容test
创建文件#!/bin/rm
,使其可执行(例如chmod 755
)并尝试通过运行./test
来执行它。现在,该文件在哪里:)
答案 1 :(得分:3)
因此,他们必须为awk命令传递
-f
选项。
是的,这是正确的。 shebang行由内核在调用时解释。如果它读取#!/usr/bin/env awk -f
,那么这意味着当该文件作为可执行文件被调用时(即,当它作为程序参数传递给七个exec
函数之一时),正确的方式“执行“它是通过执行awk -f <filename>
。换句话说:exec
函数将使用正确的参数调用解释器,而不是尝试执行文件本身(因为它不是二进制文件)。
-f
选项是必需的,因为awk(1)
默认从参数中读取程序;如果您希望它从文件中读取它,则需要-f
。
根据我的理解,这意味着awk处理输入 通过搜索具有指定模式的行来搜索文件 progfile / prog取决于你是否在awk中使用-f选项。
awk(1)
始终处理输入文件以查找匹配项。 -f
选项仅控制从中读取awk程序的位置。如果启用,则表示第一个文件名实际上是包含awk程序的文件的名称。否则,第一个文件名是第一个开始查找模式的文件。如果未指定任何文件,则只会与stdin
中的行匹配。
我们没有在#!/ usr / bin / env awk -f行中指定prog文件
内核为您做到了这一点。再一次,shebang行说:当你想执行这个文件(称之为X
)时,请用awk -f
来完成。所以它相当于awk -f X
。
如果我从awk脚本的第一行删除-f选项并运行它,我会收到以下错误:
因为那样会与:
相同$ awk ./test.awk
这是无稽之谈,因为没有-f
,它会尝试将./test.awk
解释为awk程序。所以你得到一个错误。
答案 2 :(得分:2)
#!/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
有关#!/usr/bin/env
黑客的讨论,请参阅this question和my answer。
答案 3 :(得分:1)
Shebang行将由内核解释,它将调用shebang之后指定的解释器,并将可执行文件名(您的脚本)作为参数。请参阅man 2 execve,“解释程序脚本”部分