4

我尝试运行这样的单行命令

touch ./py.py; awk 'BEGIN{print FILENAME}' ./py.py 

并期望得到结果./py.py,但只得到一个空行。但是,如果我没有BEGIN阻止,它会起作用:

touch ./py.py; awk '{print FILENAME}' ./py.py

似乎该变量在块FILENAME中不可用。BEGIN这是为什么?如何在BEGIN块中使用该变量?

4

4 回答 4

4

awk 可以在一次调用中处理多个文件(例如awk '{whatever}' file1 file2 file3)。BEGIN 块在 awk 启动时执行,在它打开第一个文件之前,而不是在每个文件的开头(END 块类似)。有人可能会争辩说,将 awk 扩展为具有每个文件的 BEGIN/END 挂钩可能很有用,但它们在我使用的任何当前版本的 awk/nawk/gawk 中都不存在......

于 2012-06-06T14:28:48.640 回答
2

事后总结:

  • gawk (GNU awk) 4或更高版本中,使用BEGINFILE而不是BEGIN确保FILENAME已定义;但是请注意,BEGINFILE顾名思义,每个输入文件都会调用 .

  • 在其他awk变体中,仅BEGIN提供,此时FILENAME尚未定义,因为根据设计,输入文件处理尚未开始。(相比之下,块FILENAME 中确实有一个值END,即最后处理的文件。)

解决方法

您可以通过内置参数访问传递给 awk的文件名ARGV参数,其中ARGV[1]报告第一个文件名参数、ARGV[2]第二个文件名参数,依此类推。

  • 请注意,选项和隐含的标准输入计算在内,因此隐含的stdin输入ARGV[1]将是一个空字符串
  • 相比之下,充当变量赋值的伪文件名确实很重要(例如,VAR=10)。

因此,假设没有伪文件名,ARGV[1]在处理[第一个]文件时,BEGIN块中的内容相当于FILENAME后面的块。

Caveat re implicit use of stdin: BSD awk (e.g., on OSX) reports implicit stdin input also as an empty string in FILENAME (in later blocks), whereas mawk and gawk report "-". All 3 variants, however, support explicit stdin input by passing - as a filename argument, in which case FILENAME returns "-" in all 3 variants.

于 2014-02-04T22:14:15.380 回答
1

确实 FILENAME 在 awk 的 BEGIN 块中不可用。事实上,awk 不会在 BEGIN 块中开始处理输入文件,因此没有设置这个内部变量。甚至这个命令:

awk 'BEGIN{print;}' ./file

不会打印文件中的任何内容。

于 2012-06-06T14:28:19.760 回答
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 块中(因此将文件作为参数忽略),我们将不得不通过使用-builtin数组的偷偷摸摸的方法来模拟这种行为,就好像awk行后面的参数一个文件一样,例如:awkARGV[]

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中做的那样),如果文件不存在则吐出一个错误。相当没有意义的国际海事组织,但是——唉,如果我们总是不得不质疑一个解决方案实际上是多么明智,我们需要一生的时间来解决它,尤其是在政治方面。:)FILENAMEBEGIN

于 2013-09-05T13:02:15.460 回答