将 gawk 的输入重定向到系统命令
Redirect input for gawk to a system command
通常 gawk 脚本会处理其标准输入的每一行。是否可以在脚本中指定一个系统命令,使用脚本其余部分中命令输出的每一行来处理?
例如考虑以下简单交互:
$ { echo "abc"; echo "def"; } | gawk '{print NR ":" [=10=]; }'
1:abc
2:def
我想在不使用管道的情况下获得相同的输出,而是将 echo 命令指定为系统命令。
我当然可以使用管道,但这会迫使我要么使用两个不同的脚本,要么在 bash 脚本中指定 gawk 脚本,我正在努力避免这种情况。
更新
前面的例子不太能代表我的用例,这个比较接近:
$ { echo "abc"; echo "def"; } | gawk '/d/ {print NR ":" [=11=]; }'
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
我相信你要找的是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
从您的所有评论来看,听起来您想要的是:
$ cat tst.awk
BEGIN {
if ( ("mktemp" | getline file) > 0 ) {
system("(echo abc; echo def) > " file)
ARGV[ARGC++] = file
}
close("mktemp")
}
{ print FILENAME, NR, [=10=] }
END {
if (file!="") {
system("rm -f \"" file "\"")
}
}
$ awk -f tst.awk
/tmp/tmp.ooAfgMNetB 1 abc
/tmp/tmp.ooAfgMNetB 2 def
但老实说,我不会这样做。您正在将 shell 擅长的(creating/destroying 文件和进程)与 awk 擅长的(处理文本)相结合。
通常 gawk 脚本会处理其标准输入的每一行。是否可以在脚本中指定一个系统命令,使用脚本其余部分中命令输出的每一行来处理?
例如考虑以下简单交互:
$ { echo "abc"; echo "def"; } | gawk '{print NR ":" [=10=]; }'
1:abc
2:def
我想在不使用管道的情况下获得相同的输出,而是将 echo 命令指定为系统命令。
我当然可以使用管道,但这会迫使我要么使用两个不同的脚本,要么在 bash 脚本中指定 gawk 脚本,我正在努力避免这种情况。
更新
前面的例子不太能代表我的用例,这个比较接近:
$ { echo "abc"; echo "def"; } | gawk '/d/ {print NR ":" [=11=]; }'
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
我相信你要找的是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
从您的所有评论来看,听起来您想要的是:
$ cat tst.awk
BEGIN {
if ( ("mktemp" | getline file) > 0 ) {
system("(echo abc; echo def) > " file)
ARGV[ARGC++] = file
}
close("mktemp")
}
{ print FILENAME, NR, [=10=] }
END {
if (file!="") {
system("rm -f \"" file "\"")
}
}
$ awk -f tst.awk
/tmp/tmp.ooAfgMNetB 1 abc
/tmp/tmp.ooAfgMNetB 2 def
但老实说,我不会这样做。您正在将 shell 擅长的(creating/destroying 文件和进程)与 awk 擅长的(处理文本)相结合。