简体   繁体   English

在bash tee中,使函数变量成为局部变量,我该如何转义?

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

I have stucked with a bash scipt which should write both to stdout and into file. 我坚持使用bash scipt,它应该同时写入stdout和文件。 I'm using functions and some variables inside them. 我正在使用函数和其中的一些变量。 Whenever I try to redirect the function to a file and print on the screen with tee I can't use the variables that I used in function, so they become local somehow. 每当我尝试将函数重定向到文件并使用tee在屏幕上打印时,我都无法使用函数中使用的变量,因此它们会以某种方式变为局部变量。 Here is simple example: 这是简单的示例:

#!/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"

Output: 输出:

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

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

Thanks in advance! 提前致谢!

EDIT: Responding on @Etan Reisner suggestion to use var 2>&1 > >(tee $LOGV) 编辑:响应@Etan Reisner建议使用var 2>&1 > >(tee $LOGV)

The only problem of this construction is that log file dosn't receive everything... 这种构造的唯一问题是日志文件无法接收所有内容...

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

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

This is a variant of BashFAQ #24 . 这是BashFAQ#24的变体。

var 2>&1 | tee $LOGV

...like any shell pipeline, has the option to run the function var inside a subprocess -- and, in practice, behaves this way in bash. ...像任何Shell管道一样,可以选择在子进程中运行var函数,并且实际上在bash中具有这种行为。 (The POSIX sh specification leaves the details of which pipeline components, if any, run inside the parent shell undefined). (POSIX sh规范未定义哪些管道组件(如果有)在父外壳程序内部运行的详细信息)。


Avoiding this is as simple as not using a pipeline. 避免这种情况就像不使用管道一样简单。

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

...uses process substitution (a ksh extension adopted by bash, not present in POSIX sh) to represent the tee subprocess through a filename (in the form /dev/fd/## on modern Linux) which output can be redirected to without moving the function into a pipeline. ...使用进程替换(bash采用的ksh扩展名,在POSIX sh中不存在)通过文件名(在现代Linux上为/dev/fd/##形式)表示tee子进程,可以将输出重定向到将功能移动到管道中。


If you want to ensure that tee exits before other commands run, use a lock: 如果要确保在其他命令运行之前退出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"

Incidentally, if you want to run multiple commands with their output being piped in this way, you should invoke the tee only once, and feed into it as appropriate: 顺便说一句,如果您要运行多个命令,并且以这种方式将它们的输出通过管道传输,则应该仅调用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.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM