7

我有一个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

4 回答 4

11

如果您使用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变量将保留它以前的任何值。

于 2012-09-13T15:41:22.100 回答
5

代替:

BEGIN {FS=":"}

利用:

FNR == 1 {FS=":"}
于 2012-09-13T16:02:27.783 回答
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

于 2012-09-13T15:43:46.017 回答
0

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

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

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

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

于 2018-10-08T15:09:41.030 回答