如何让awk处理它解析的每个文件的BEGIN块?

时间:2012-09-13 15:21:21

标签: bash awk cygwin

我有一个awk脚本,我正在对一对文件运行。我这样称呼它:

awk -f script.awk file1 file2

script.awk看起来像这样:

BEGIN {FS=":"}
{ if( NR == 1 )
    { 
      var=$2
      FS=" "
    }
   else print var,"|",$0
}

每个文件的第一行是冒号分隔的。对于每一行,我希望它返回默认的空白文件分隔符。

这适用于第一个文件,但是因为FS在每个文件后没有重置为:而失败,因为BEGIN块只处理了一次。

tldr:有没有办法让awk处理BEGIN块一次为我传递的每个文件?

我在cygwin bash上运行它,以防万一。

4 个答案:

答案 0 :(得分:8)

如果您使用的是gawk版本4或更高版本,则会出现BEGINFILE块。从手册:

  

BEGINFILE和ENDFILE是其他特殊模式,它们的主体在读取第一个之前执行   记录每个命令行输入文件并在读取每个文件的最后一条记录之后。在BEGINFILE里面   规则,如果文件可以成功打开,ERRNO的值将为空字符串。否则,那里   是文件的一些问题,代码应该使用nextfile跳过它。如果不这样做,gawk会产生   对于无法打开的文件,它通常会出现致命错误。

例如:

touch a b c
awk 'BEGINFILE { print "Processing: " FILENAME }' a b c

输出:

Processing: a
Processing: b
Processing: c

编辑 - 更便携的方式

DennisWilliamson 所述,您可以在脚本开头使用FNR == 1获得类似的效果。除此之外,您可以直接从命令行更改FS,例如:

awk -f script.awk FS=':' file1 FS=' ' file2

此处FS变量将保留以前的任何值。

答案 1 :(得分:4)

而不是:

BEGIN {FS=":"}

使用:

FNR == 1 {FS=":"}

答案 2 :(得分:3)

FNR变量可以为您提供帮助。它与NR相同,除了它在文件范围内,因此每个输入文件都会重置为1。

http://unstableme.blogspot.ca/2009/01/difference-between-awk-nr-and-fnr.html
http://www.unix.com/shell-programming-scripting/46931-awk-different-between-nr-fnr.html

答案 3 :(得分:0)

当您想要POSIX兼容版本时,最好的方法是:

(FNR == 1) { FS=":"; $0=$0 }

这表明,如果文件记录号(FNR)等于1,我们将重置字段分隔符FS。但是,您还需要重新解析$0并重置所有其他字段的值和NF内置变量。

当且仅当记录分隔符(BEGINFILE)保持不变时,这等效于GNU awk 4.x RS