从 GNU awk 协进程非阻塞读取?
Non blocking read from GNU awk coprocess?
我想使用 gawk
实现脚本的增量执行,以便在文档中交错脚本源和脚本输出。
我们的想法是将脚本行读入 awk 以打印它们,并将它们通过管道传输到适当的解释器中。然后,在输入文件的队列中,读取协处理的任何输出并将其打印到标准输出。不过好像在循环coprocess输出之前必须要知道产生了多少输出。
有什么方法可以从协进程进行非阻塞读取吗?
function script_checkpoint() {
while(("python3" |& getline output) > 0)
print output
}
/^# checkpoint/ { script_checkpoint(); next }
{ print; print [=10=] |& "python3" }
END { script_checkpoint() }
编辑:我试图在不使用协进程的情况下实现这一点,方法是将输入行缓冲到检查点,然后让解释器打印到标准输出本身,但解释器始终缓冲其输出,直到流关闭。在程序结束以保留其内部状态之前,我不想关闭它。
编辑:更清楚地表明我的第一个预期用例是 运行 python 脚本。这是一个示例 input/output 对。
print('first line')
# checkpoint
print('second line')
应该导致
print('first line')
first line
print('second line')
second line
听起来你正在尝试做这样的事情:
BEGIN { cmd="/my/python/script/path" }
function script_checkpoint( output) {
close(cmd,"to")
while ( (cmd |& getline output) > 0 ) {
print output
}
close(cmd)
}
/^# checkpoint/ {
script_checkpoint()
next
}
{
print
print |& cmd
}
END { script_checkpoint() }
一般问题:
while ((interpreter |& getline output) > 0)
运行s 直到它看到 EOF 但是...
interpreter
不会 end/terminate/exit,因此不会发送 EOF 所以 ...
awk
在等待 interpreter
发送更多数据时挂起,因此 ...
- 我们最终遇到了死锁情况(
awk
等待来自 interpreter
的输入;interpreter
等待来自 awk
的输入)
假设:
- 需要在整个 运行 期间保持对
interpreter
的一次调用(根据 OP 的评论);最终结果:awk
不能依赖于 interpreter
发送 EOF
interpreter
可以修改(生成额外的输出)
awk
脚本无法知道 interpreter
将生成多少行输出
一个想法是在 awk
和 interpreter
之间设置握手。在 while ((interpreter |& getline output) > 0)
循环中,我们将测试我们的握手,当我们看到它跳出循环并 return 回到主 awk
脚本时。
出于演示目的,我将使用一个简单的 bash
脚本来执行一些握手处理,否则只是将它从标准输入读取的内容打印到标准输出:
$ cat interpreter
#!/usr/bin/bash
while read -r line
do
if [[ "${line}" = 'checkpoint' ]] # received 'checkpoint' handshake?
then
echo "CHECKPOINT" # send "CHECKPOINT" handshake/acknowledgement
continue
else
echo "interpreter: $line"
fi
done
演示 awk
带有握手逻辑的代码:
awk '
function script_checkpoint() {
while (( cmd |& getline output) > 0) {
if ( output == "CHECKPOINT" ) # received "CHECKPOINT" handshake/acknowledgement?
break
print output
}
}
BEGIN { cmd= "./interpreter" }
/^# checkpoint/ { print "checkpoint" |& cmd # send "checkpoint" handshake
script_checkpoint()
next
}
{ print "awk: " [=11=]
print [=11=] |& cmd
}
END { print "awk: last checkpoint" # in case last line of input is not "# checkpoint" we will ...
print "checkpoint" |& cmd # send one last "checkpoint" handshake
script_checkpoint()
print "awk: done"
}
' test.dat
示例输入文件:
$ cat test.dat
line1
line2
# checkpoint
line3
line4
# checkpoint
line5
输出:
awk: line1
awk: line2
interpreter: line1
interpreter: line2
awk: line3
awk: line4
interpreter: line3
interpreter: line4
awk: line5
awk: last checkpoint
interpreter: line5
awk: done
备注:
awk
仍然会在 interpreter
崩溃的情况下挂起 and/or 无法发回 CHECKPOINT
握手
- 如果字符串
checkpoint
and/or CHECKPOINT
可以出现在 'normal' 数据流中,则更新代码以使用数据流中不期望的字符串
我想使用 gawk
实现脚本的增量执行,以便在文档中交错脚本源和脚本输出。
我们的想法是将脚本行读入 awk 以打印它们,并将它们通过管道传输到适当的解释器中。然后,在输入文件的队列中,读取协处理的任何输出并将其打印到标准输出。不过好像在循环coprocess输出之前必须要知道产生了多少输出。
有什么方法可以从协进程进行非阻塞读取吗?
function script_checkpoint() {
while(("python3" |& getline output) > 0)
print output
}
/^# checkpoint/ { script_checkpoint(); next }
{ print; print [=10=] |& "python3" }
END { script_checkpoint() }
编辑:我试图在不使用协进程的情况下实现这一点,方法是将输入行缓冲到检查点,然后让解释器打印到标准输出本身,但解释器始终缓冲其输出,直到流关闭。在程序结束以保留其内部状态之前,我不想关闭它。
编辑:更清楚地表明我的第一个预期用例是 运行 python 脚本。这是一个示例 input/output 对。
print('first line')
# checkpoint
print('second line')
应该导致
print('first line')
first line
print('second line')
second line
听起来你正在尝试做这样的事情:
BEGIN { cmd="/my/python/script/path" }
function script_checkpoint( output) {
close(cmd,"to")
while ( (cmd |& getline output) > 0 ) {
print output
}
close(cmd)
}
/^# checkpoint/ {
script_checkpoint()
next
}
{
print
print |& cmd
}
END { script_checkpoint() }
一般问题:
while ((interpreter |& getline output) > 0)
运行s 直到它看到 EOF 但是...interpreter
不会 end/terminate/exit,因此不会发送 EOF 所以 ...awk
在等待interpreter
发送更多数据时挂起,因此 ...- 我们最终遇到了死锁情况(
awk
等待来自interpreter
的输入;interpreter
等待来自awk
的输入)
假设:
- 需要在整个 运行 期间保持对
interpreter
的一次调用(根据 OP 的评论);最终结果:awk
不能依赖于interpreter
发送 EOF interpreter
可以修改(生成额外的输出)awk
脚本无法知道interpreter
将生成多少行输出
一个想法是在 awk
和 interpreter
之间设置握手。在 while ((interpreter |& getline output) > 0)
循环中,我们将测试我们的握手,当我们看到它跳出循环并 return 回到主 awk
脚本时。
出于演示目的,我将使用一个简单的 bash
脚本来执行一些握手处理,否则只是将它从标准输入读取的内容打印到标准输出:
$ cat interpreter
#!/usr/bin/bash
while read -r line
do
if [[ "${line}" = 'checkpoint' ]] # received 'checkpoint' handshake?
then
echo "CHECKPOINT" # send "CHECKPOINT" handshake/acknowledgement
continue
else
echo "interpreter: $line"
fi
done
演示 awk
带有握手逻辑的代码:
awk '
function script_checkpoint() {
while (( cmd |& getline output) > 0) {
if ( output == "CHECKPOINT" ) # received "CHECKPOINT" handshake/acknowledgement?
break
print output
}
}
BEGIN { cmd= "./interpreter" }
/^# checkpoint/ { print "checkpoint" |& cmd # send "checkpoint" handshake
script_checkpoint()
next
}
{ print "awk: " [=11=]
print [=11=] |& cmd
}
END { print "awk: last checkpoint" # in case last line of input is not "# checkpoint" we will ...
print "checkpoint" |& cmd # send one last "checkpoint" handshake
script_checkpoint()
print "awk: done"
}
' test.dat
示例输入文件:
$ cat test.dat
line1
line2
# checkpoint
line3
line4
# checkpoint
line5
输出:
awk: line1
awk: line2
interpreter: line1
interpreter: line2
awk: line3
awk: line4
interpreter: line3
interpreter: line4
awk: line5
awk: last checkpoint
interpreter: line5
awk: done
备注:
awk
仍然会在interpreter
崩溃的情况下挂起 and/or 无法发回CHECKPOINT
握手- 如果字符串
checkpoint
and/orCHECKPOINT
可以出现在 'normal' 数据流中,则更新代码以使用数据流中不期望的字符串