如何在Bash管道中通过函数修改全局变量?
Bash管道中修改全局变量的无临时文件解决办法
问题背景
尝试在Bash管道内的函数中修改全局变量时,变量值无法同步到主shell。示例代码及输出如下:
示例代码:
#!/bin/bash declare GVAR="abc" func1() { read GVAR echo>&2 "func1: GVAR is $GVAR" } func2() { echo "xyz" } func2 | func1 echo>&2 "main: GVAR is $GVAR"
输出结果:
func1: GVAR is xyz main: GVAR is abc
原因是Bash管道中的每个命令都会在独立子shell中执行,子shell内的变量修改不会回溯到父shell。尝试过shopt -s lastpipe但仅适用于管道最后一个命令,无法满足“分流数据后继续传递给其他命令”的需求,因此需要无需临时文件的替代方案。
替代方案1:进程替换+重定向
利用进程替换让函数在当前shell执行,同时保留数据传递能力:
#!/bin/bash declare GVAR="abc" func1() { # 读取数据到GVAR,同时将数据输出给后续命令 read -r line GVAR="$line" echo>&2 "func1: GVAR is $GVAR" echo "$line" } func2() { echo "xyz" } # func1在当前shell运行,接收func2的输出,同时输出可继续管道 func1 < <(func2) | your_next_command echo>&2 "main: GVAR is $GVAR"
< <(func2)会把func2的输出作为func1的标准输入,且func1运行在主shell中,修改的GVAR会直接生效。func1中echo读取到的内容,就能把数据传递给后续命令。
替代方案2:自定义文件描述符分流
通过文件描述符复制数据流,让函数在主shell中读取数据:
#!/bin/bash declare GVAR="abc" func1() { read -r GVAR <&3 # 从文件描述符3读取数据 echo>&2 "func1: GVAR is $GVAR" } func2() { echo "xyz" } # 将func2的输出同时发给标准输出(给后续命令)和文件描述符3(给func1) func2 | tee >(exec 3<&0) | your_next_command & wait # 等待后台管道执行完毕 func1 echo>&2 "main: GVAR is $GVAR"
tee >(exec 3<&0)复制func2的输出到文件描述符3,func1在主shell中读取该描述符的内容,变量修改直接生效,同时标准输出的数据仍能传给后续命令。
替代方案3:使用协程(coproc)
协程可以在后台运行命令,同时让主shell直接访问其输出管道:
#!/bin/bash declare GVAR="abc" func2() { echo "xyz" } # 启动协程运行func2,获取其输出管道 coproc func2 # 从协程管道读取数据到GVAR read -r GVAR <&"${COPROC[0]}" echo>&2 "main: GVAR is $GVAR" # 将数据继续传递给后续命令 echo "$GVAR" | your_next_command
协程的输出管道由${COPROC[0]}暴露在主shell中,直接读取即可修改全局变量,后续还能把变量值输出给其他命令。
内容的提问来源于stack exchange,提问作者Albert Camu
相关产品推荐
相关产品推荐

