具有相反效果的 awk 系统调用

具有相反效果的 awk 系统调用

我有一个数据文件,其中多个数据块包含在特定关键字 ( DATA, END) 之间。我用来awk根据从所述块中获取的文件名将数据块提取到单独的文件中。由于某些数据块共享相同的名称,如果文件(“ blockname”)已经存在,我将使用递增的整数重命名每个输出文件:

#cat input.file
useless stuff1
DATA blockname1
data1
data1
END
useless stuff2
DATA blockname2
data2
data2
END
useless stuff3
DATA blockname1
data3
data3
END
useless stuff4

预期将是三个输出文件blockname1blockname2blockname1_1(注意最后一个文件如何分配一个整数)

#cat blockname1
DATA blockname1
data1
data1
END

(其他人相应地...)

现在以下脚本可以按我想要的方式工作:

awk '/DATA/,/END/ {
     if ( $1 ~ /DATA/ )
       { block=$2 ; i=0 ; file=block
         while ( system("test ! -e " file ) )
           { i++ ; file=block"_"i ; print file }
       }
       print $0 > file
     }' input.file

我的问题在于while循环及其系统调用:

我希望system("test -e " file)当存在时为 TRUE,如果尚不存在file则为 FALSE ,即循环仅在存在时才开始运行,如果(新的)尚不存在则中断。filewhilefilefile

但是,如果我使用system("test -e " file)(并使用 使其变得冗长print file),我将有一个同名的无限循环,并且带有递增的整数后缀,相反system("test !-e " file)会给出所需的结果。

所以这与我的预期完全相反。

答案1

好的,我想:问题在于 的退出状态testwhile循环条件之间 TRUE 和 FALSE 的不同定义awk

test命令导致退出代码0为 TRUE,负命令导致退出代码1为 FALSE。

但是,在awk循环中while解释0为 FALSE 和1TRUE,因此定义完全相反。

举个例子:

awk '{ while ( 0 ) ; { print "0" } }' file

不会产生任何输出,而

awk '{ while (1) ; { print "1" } }' file

将打印无限1s。

因此,最佳实践是在这种组合中明确

while ( system("command") == 0 )

或者

while ( system("command") == 1 )

分别。

所以就我而言

while ( system("test -e " file ) == 0 ) 

显示预期的行为。

答案2

awk system()返回您运行的命令的退出状态 - 0 表示成功,如果不成功则返回 != 0。对于简单的示例,您可以尝试运行:

v = system("date");

v 将是 0

如果你运行:

v = system("dat");

v 可能是 127 或不同于 0 的值,如果 dat 命令丢失或未找到,则操作系统返回错误。

答案3

如果我理解你的意思,目标是将 input.file 的内容提取到各种文件中,避免丢失同名的块。

如果是这种情况,并且如果目标目录在提取之前始终为空,那么有一个更好(更快)的解决方案:

awk '
/DATA/{
    block=$2;
    n = blocks[block]++;
    file=block (n? "_" n: "");  
}
/DATA/,/END/{
    print > file
}' input.file

这样 awk 不需要执行 N 次新的 shell 来测试文件是否存在。

笔记:

  • 不需要 BEGIN 块,因为 awk 的字段分隔符已经是空格。
  • '\'行尾不需要,因为单引号已经是多行了。

相关内容