2

私は、標準出力とファイルの両方に書き込む必要があるbash sciptにこだわっています。関数とその中にいくつかの変数を使用しています。関数をファイルにリダイレクトして画面に印刷しようとすると、関数で使用した変数を使用できないため、何らかの形でローカルになります。簡単な例を次に示します。

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

1 に答える 1

6

これはBashFAQ #24の変種です。

var 2>&1 | tee $LOGV

...他のシェルパイプラインと同様varに、サブプロセス内で関数を実行するオプションがあり、実際には、bash でこのように動作します。(POSIX sh 仕様では、親シェル内で実行されるパイプライン コンポーネントがある場合、その詳細は未定義のままです)。


これを回避するには、パイプラインを使用しないのと同じくらい簡単です。

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

...プロセス置換 (POSIX sh には存在しない、bash によって採用された ksh 拡張機能) を使用して、関数をパイプラインに移動せずに出力をリダイレクトできるteeファイル名 (最新の Linux の形式) を介してサブプロセスを表します。/dev/fd/##


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.
于 2015-07-22T01:20:57.847 に答える