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

╄→尐↘猪︶ㄣ 提交于 2020-01-15 08:17:30

问题


I have stucked with a bash scipt which should write both to stdout and into file. 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. 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)

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:

回答1:


This is a variant of 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. (The POSIX sh specification leaves the details of which pipeline components, if any, run inside the parent shell undefined).


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.


If you want to ensure that tee exits before other commands run, use a lock:

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

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


来源:https://stackoverflow.com/questions/31551115/in-bash-tee-is-making-function-variables-local-how-do-i-escape-this

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!