我尝试像这样运行一行命令
touch ./py.py; awk 'BEGIN{print FILENAME}' ./py.py
并期望得到结果./py.py
,但只得到一个空行。但是,如果我在没有BEGIN
块的情况下执行此操作,则可以:
touch ./py.py; awk '{print FILENAME}' ./py.py
似乎FILENAME
块中没有BEGIN
变量。这是为什么?如何在BEGIN
块中使用该变量?
答案 0 :(得分:4)
Awk可以在一次调用中处理多个文件(例如awk '{whatever}' file1 file2 file3
)。当awk启动时,在打开第一个文件之前执行BEGIN块,而不是在每个文件的开头执行(END块类似)。有人可能会说,将awk扩展为具有每个文件的BEGIN / END挂钩可能会有用,但是在我使用的任何当前版本的awk / nawk / gawk中都不存在...
答案 1 :(得分:1)
确实,在awk的BEGIN块中没有FILENAME。事实上,awk没有开始处理BEGIN块中的输入文件,因此未设置此内部变量。甚至这个命令:
awk 'BEGIN{print;}' ./file
不会从文件中打印任何内容。
答案 2 :(得分:1)
总结后见之明的好处:
在gawk (GNU awk) 4
或更高版本中,使用BEGINFILE
代替BEGIN
可确保定义FILENAME
;但请注意,BEGINFILE
,顾名思义,是为每个输入文件调用的。
在仅提供awk
的其他BEGIN
变体中, FILENAME
尚未定义,因为,按设计, 输入文件处理尚未开始。 (相比之下,FILENAME
在END
块中有一个值,即已处理的 last 文件。)
解决方法强>:
您可以通过内置参数ARGV
访问传递给awk的文件名参数,其中ARGV[1]
报告第一个文件名参数ARGV[2]
第二,等等。
stdin
输入ARGV[1]
将是空字符串。VAR=10
)。因此,假设没有伪文件名,ARGV[1]
块中的BEGIN
在后续块中等同于FILENAME
,而正在处理[first]文件。
警告隐含使用stdin
:BSD awk
(例如,在OSX上)报告隐式stdin
输入也作为{{1}中的空字符串(在后面的块中),而FILENAME
和mawk
报告gawk
。
但是,所有3个变体都通过将"-"
作为文件名参数传递来支持显式 stdin
输入,在这种情况下,-
会在所有3中返回FILENAME
变体。
答案 3 :(得分:0)
虽然我不知道对此有何深层意义,但我仍然可以想出一个黑客。我不会称之为“解决方案”。不过,这是一个很好的方式来消磨时间。 ;)
这是最初的工作单线之一:
touch ./py.py; awk '{print FILENAME}' ./py.py
为此,您必须知道awk
物理检查媒体上是否存在该文件。因此,如果我们尝试过这样的事情:
awk '{print FILENAME}' ./py2.py
awk
将获得拯救:
awk: cmd. line:1: fatal: cannot open file `./py2.py' for reading (No such file or directory)
好的。所以如果我们在一个BEGIN块中(因此将文件作为参数被忽略),我们必须模拟这种行为,好像awk
背后的参数一样line 是一个文件,通过偷偷摸摸的方法使用awk
- 内置ARGV[]
数组,e。 G。像这样:
awk 'BEGIN {$0 = ARGV[1]; if ((getline <$0) == -1) print "ERROR: File not found: " $0; else print ARGV[1]}' ./py.py
这将给出结果:
./py.py
到目前为止,这么好。现在为什么不刻意使用我们在物理媒体上没有的文件:
awk 'BEGIN {$0 = ARGV[1]; if ((getline <$0) == -1) print "ERROR: File not found: " $0; else print ARGV[1]}' ./py2.py
将导致
ERROR: File not found: ./py2.py
因此,我们实际检查文件是否存在(如awk
在非FILENAME
块中与BEGIN
一样)并在文件不存在时吐出错误。
相当无意义的IMO,但是 - 唉,如果我们总是不得不质疑一个解决方案实际上是多么明智,我们需要一生一世的时间,特别是在政治方面。 :)