将gawk的输入重定向到系统命令

时间:2015-02-10 08:47:14

标签: awk

通常gawk脚本处理其标准输入的每一行。是否有可能在脚本中指定一个系统命令,在脚本的其余部分使用该命令输出的每一行进程?

例如,考虑以下简单的交互:

$ { echo "abc"; echo "def"; } | gawk '{print NR ":" $0; }'
1:abc
2:def

我想在不使用管道的情况下获得相同的输出,而是将echo命令指定为系统命令。

我当然可以使用管道,但这会迫使我使用两个不同的脚本或在bash脚本中指定gawk脚本,我试图避免这种情况。

更新

前面的例子并不能完全代表我的用例,这有点接近:

$ { echo "abc"; echo "def"; } | gawk '/d/ {print NR ":" $0; }'
2:def

更新2

并行的shell脚本如下。没有exec行,脚本会从stdin读取;使用exec它将使用行作为输入的命令:

/tmp> cat t.sh
#!/bin/bash

exec 0< <(echo abc; echo def)
while read l; do
  echo "line:" $l
done
/tmp> ./t.sh 
line: abc
line: def

2 个答案:

答案 0 :(得分:1)

我相信您正在寻找的是getline

awk '{ while ( ("echo abc; echo def" | getline line) > 0){ print line} }' <<< ''
abc
def

调整你的答案第二个例子:

awk '{ while ( ("echo abc; echo def" | getline line) > 0){ counter++; if ( line ~ /d/){print counter":"line} } }' <<< ''
2:def

让我们分解一下:

awk '{ 
       cmd = "echo abc; echo def"

       # line below will create a line variable containing the ouptut of cmd
       while ( ( cmd | getline line) > 0){ 

          # we need a counter because NR will not work for us
          counter++; 

          # if the line contais the letter d
          if ( line ~ /d/){ 
             print counter":"line
          } 
        } 
    }' <<< ''
    2:def

答案 1 :(得分:1)

从你的所有评论中,听起来都像你想要的那样:

$ cat tst.awk
BEGIN {
    if ( ("mktemp" | getline file) > 0 ) {
        system("(echo abc; echo def) > " file)
        ARGV[ARGC++] = file
    }
    close("mktemp")
}

{ print FILENAME, NR, $0 }

END {
    if (file!="") {
        system("rm -f \"" file "\"")
    }
}

$ awk -f tst.awk
/tmp/tmp.ooAfgMNetB 1 abc
/tmp/tmp.ooAfgMNetB 2 def
但老实说,我不会这样做。你正在使用awk擅长的东西(操纵文本)来修改shell擅长的东西(创建/销毁文件和进程)。