在 bash 中,tee 正在使函数变量成为局部变量,我该如何避免这种情况?

In bash tee is making function variables local, how do I escape this?

我坚持使用 bash scipt,它应该同时写入标准输出和文件。我正在使用函数和其中的一些变量。每当我尝试将函数重定向到文件并使用 tee 在屏幕上打印时,我都无法使用我在函数中使用的变量,因此它们以某种方式成为本地变量。 这是一个简单的例子:

#!/bin/bash
LOGV=/root/log

function var()
{
echo -e "Please, insert VAR value:\n"
read -re VAR
}
var 2>&1 | tee $LOGV
echo "This is VAR:$VAR"

输出:

[root@testbox ~]# ./var.sh   
Please, insert VAR value:

foo
This is VAR:
[root@testbox ~]#

提前致谢!

编辑: 回应@Etan Reisner 建议使用 var 2>&1 > >(tee $LOGV)

这个构造的唯一问题是日志文件没有接收到所有内容...

[root@testbox~]# ./var.sh
Please, insert VAR value: 

foo 
This is VAR:foo
[root@testbox ~]# cat log 
Please, insert VAR value:

这是 BashFAQ #24 的变体。

var 2>&1 | tee $LOGV

...像任何 shell 管道一样,可以选择 运行 子进程内的函数 var -- 实际上,在 bash. (POSIX sh 规范留下了父 shell 未定义的管道组件的详细信息,如果有的话,运行。


避免这种情况就像不使用管道一样简单。

var > >(tee "$LOGV") 2>&1

...使用进程替换([=35= 采用的 ksh 扩展,POSIX sh 中不存在)通过文件名(格式为 /dev/fd/## 在现代 Linux) 中可以重定向到哪个输出,而无需将函数移动到管道中。


如果要确保 tee 在其他命令 运行 之前退出,请使用锁:

#!/bin/bash
logv=/tmp/log

collect_var() {
        echo "value for var:"
        read -re var
}
collect_var > >(logv="$logv" flock "$logv" -c 'exec tee "$logv"') 2>&1
flock "$logv" -c true # wait for tee to exit

echo "This is var: $var"

顺便说一下,如果你想 运行 多个命令的输出以这种方式通过管道传输,你应该只调用 tee 一次,并适当地输入它:

#!/bin/bash
logv=/tmp/log
collect_var() { echo "value for var:"; read -re var; }

exec 3> >(logv="$logv" flock "$logv" -c 'exec tee "$logv"') # open output to log
collect_var >&3 2>&3         # run function, sending stdout/stderr to log
echo "This is var: $var" >&3 # ...and optionally run other commands the same way
exec 3>&-                    # close output
flock "$logv" -c true        # ...and wait for tee to finish flushing and exit.