如何通过文件列值循环命令?

如何通过文件列值循环命令?

我有一个像这样的简单命令

 grep 'X' results.dat | awk '{print $NF}'  > Y.dat

我想循环这个命令Xs第 1 栏以及相应的伊苏第2栏同一文件的例如。名称

NAMES 文件的格式为

C11-C12     p01
C13-C14-C17 P02
etc ..

所以循环中的前两个步骤应该是这样的

grep 'C11-C12' results.dat | awk '{print $NF}'  > p01.dat
grep 'C13-C14-C17' results.dat | awk '{print $NF}'  > p02.dat

答案1

不需要在 shell 中循环的解决方案:

awk 'pass==1 {  Xpatt[NR] = $1; Yfile[NR] = $2 ".dat"; printf "" > Yfile[NR] }
     pass==2 {
                for (i in Xpatt) {
                        if ($0 ~ Xpatt[i]) print $NF > Yfile[i]
                }
             }' pass=1 NAMES pass=2 results.dat
  • 首先, awk允许您在程序之后将变量赋值指定为命令行参数,与文件名混合,而不是使用-v.它们在命令行中的位置所建议的处理序列中的点处执行。所以,在上面的命令中,

    1. pass设置为 1,
    2. 文件NAMES已处理,
    3. pass设置为 2,然后
    4. 文件results.dat已处理。

    pass=1我想我可以用 a-v或 在一个块中设置BEGIN

    我使用pass变量来告诉我正在读取哪个文件。这通常是通过NR与进行比较来完成的FNR,但如果文件为空,则可能会导致错误指示。

    (严格来说,我认为这个脚本应该检查两个文件是否为空,因为在这种情况下,没有任何工作要做。)

  • pass==1(我们正在读取文件)时,保存该文件第 1 列和第 2 列(和)NAMES中的 X 和 Y 值(图案和文件名) 。创建输出文件 ( ),因为如果我们不在此处执行此操作,我们将不会获得文件中不存在的模式的(空)输出文件。 (如果您同意,请省略该声明。)$1$2Yfile[NR]results.datprintf
  • pass==2(我们正在读取results.dat文件)时,循环遍历文件中的模式NAMES并将与模式匹配的每一行的最后一个单词打印到相应的文件中 - 即相当于 OP 的grep X … | awk '{print $NF}' > Y.dat命令。

答案2

重击解决方案:

while read X Y remainder || [[ -n ${Y} ]]; do
    awk -v X="$X" '$0 ~ $X {print $NF}' results.dat > "$Y".dat
done < NAMES
  • 通常,while IFS="q" read X Y remainder; do ...; done < NAMES将迭代 中的行NAMES。它将根据IFS(内部字段分隔符)的值分隔每行中的值。在此示例中,IFS设置为字母qIFS默认为空白(空格字符、制表符或换行符)。第一个字段分配给变量X,第二个字段分配给Y,该行的其余部分分配给remainder

    也可以看看:将文件中的列读取到单独的变量中(Unix.SE)。

    在上面的解决方案中,IFS没有指定,因为我认为您的字段已经以空格分隔。

    注意:如果文件中的字段NAMES包含反斜杠,则需要使用 来read -r防止read将反斜杠解释为转义序列。

  • ... remainder || [[ -n ${remainder} ]]部分处理两件事:任何额外的字段(如果有)都存储在remainder;并处理输入文件的最后一行不以换行符结尾的情况\nread遇到 EOF 时返回非零退出代码)。

    也可以看看:逐行读取文件并将值分配给变量(所以)。

  • grep完全消除: awk -v X="$X" '$0 ~ $X {print $NF}' results.dat > "$Y".dat.该-v选项awk定义可在脚本中使用的变量awk

相关内容