通常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
答案 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擅长的东西(创建/销毁文件和进程)。