我在bash中有以下行。
(sleep 1 ; echo "foo" ; sleep 1 ; echo "bar" ; sleep 30) | nc localhost 2222 \
| grep -m1 "baz"
这打印" baz" (如果/当TCP连接的另一端发送它时)并在32秒后退出。
我想要它做的是提前退出sleep 30
如果它看到" baz"。 -m标志退出grep,但不会终止整行。
我怎样才能在bash中实现这一点(如果可能的话,不使用expect
)?
更新:当且仅当服务器尝试在baz之后发送内容时,上面的代码才会退出。这并不能解决这个问题,因为服务器可能几分钟都没有发送任何内容。
答案 0 :(得分:3)
你可以抓住你正在打开的子壳的pid。然后,这样的事情应该:
( echo "start"; sleep 1; echo $BASHPID > /tmp/subpid; echo "hello"; sleep 20; ) \
| ( sleep 1; subpid=$(cat /tmp/subpid); grep -m1 hello && kill $subpid )
也就是说,将子shell的id存储在临时文件中,然后继续描述。
在管道的另一端,您读取文件的内容(sleep 1
以确保它已由初始子shell写入文件中),并且当您找到带有{{{1}的内容时1}},你杀了它。
来自grep
:
BASHPID
扩展为当前bash进程的进程ID。这有所不同 在某些情况下来自$$,例如没有的子壳 要求重新初始化bash。
致记:
答案 1 :(得分:3)
如果您喜欢Bash的深奥,可以使用coproc
。
coproc { { sleep 1; echo "foo"; sleep 1; echo "bar"; sleep 30; } | nc localhost 2222; }
grep -m1 baz <&${COPROC[0]}
[[ $COPROC_PID ]] && kill $COPROC_PID
在这里,我们正在使用coproc
来运行
{ { sleep 1; echo "foo"; sleep 1; echo "bar"; sleep 30; } | nc localhost 2222; }
在后台。 coproc
注意在${COPROC[0]}
和${COPROC[1]}
中设置的文件描述符中重定向此复合命令的标准输出和标准输入。此外,此作业的PID
位于COPROC_PID
。然后,我们使用后台作业的标准输出提供grep
。当我们完成工作时,很容易就能完成工作。
答案 2 :(得分:1)
突然根据Jidder的评论找到了解决方案。
(sleep 1 ; echo "foo" ; sleep 1 ; echo "bar" ; for i in `seq 1 30`; do echo -n '.'; sleep 1; done) | grep -m1 "bar"
只是在循环中睡觉不起作用。但是在添加echo -n '.'
之后它才有效。似乎写入封闭管道的尝试导致中止。虽然我已经测试过没有nc。
答案 3 :(得分:1)
我相信你真的需要使用expect
(http://expect.sourceforge.net/,并且有适用于大多数操作系统和发行版的软件包。)
否则你将很难处理某些案例并摆脱缓冲等等。期待它适合你(......好吧,一旦你写了正确的脚本,除了处理所有(或大多数)案件的脚本)(对于初稿,您可以使用autoexpect(http://linux.die.net/man/1/autoexpect),但您需要添加变体(处理&#34;错误的密码&#34;消息等))
Expect是一个老工具(并且基于,iirc,基于Tcl),但实际上并没有最好的工具来发送输入和等待输出(并根据输出做出不同反应)& #34;