如何在Bash中实现当命令输出变化时自动运行指定程序
这个需求在监控外部程序输出、触发联动操作的场景里挺常见的,给你几个实用的Bash方案,都不需要修改foo本身:
方案1:用
while read逐行捕获触发(最可靠) 这是最通用也最可控的方式,通过管道把foo的输出传给Bash的read命令,每读取到一行就执行一次目标程序。
假设你要触发的程序叫bar,直接这么写:
./foo | while IFS= read -r line; do # 运行你的目标程序 ./bar # 如果需要把foo的输出内容传给bar,改成下面这样: # ./bar "$line" done
这里的参数是为了保证读取的准确性:
IFS=避免read自动去掉行首/行尾的空白字符-r禁止反斜杠转义,防止输出里的特殊字符被错误解析
如果bar执行耗时较长,这个循环会等bar跑完再处理下一行,不会出现并发堆积;如果需要并行处理,可以在./bar后面加&把它放到后台,但要注意进程管理哦。
方案2:用
xargs快速实现(极简版) 如果你的需求很简单——不需要处理行内容,只是每有一行输出就跑一次bar,xargs能一行搞定:
./foo | xargs -L 1 ./bar
-L 1表示每读取1行就执行一次后续命令- 默认情况下,
xargs会把每行内容作为参数传给bar,比如foo输出hi,就会执行./bar hi
如果foo的输出里有空格、引号这类特殊字符,记得加上-d '\n'强制按换行分割,避免xargs错误解析:
./foo | xargs -d '\n' -L 1 ./bar
方案3:解决输出缓冲问题(可选)
有时候你会发现foo的输出不是实时触发的——这是因为很多程序在输出到管道时,会把标准输出从行缓冲改成块缓冲,要等缓冲区满了才会输出内容。这时候用stdbuf强制foo行缓冲输出即可:
stdbuf -oL ./foo | while IFS= read -r line; do ./bar "$line" done
-oL表示把foo的标准输出设置为行缓冲模式,这样每输出一行就立刻刷新到管道,不会堆积。
测试验证
你可以先模拟foo的行为来测试方案,用这个命令代替./foo:
while true; do echo "test line $(date)"; sleep 1; done
把它和上面的任意方案结合,就能看到每秒都会触发一次bar啦。
内容的提问来源于stack exchange,提问作者Enx
相关产品推荐
相关产品推荐

