変数の範囲が影響を受けないように、サブシェルを使用せずにティーアクションを複製します。

変数の範囲が影響を受けないように、サブシェルを使用せずにティーアクションを複製します。

BASHのコマンド・グループ出力をSTDOUTおよびログ・ファイルとしてキャプチャーする必要があります。コマンドとその出力にグループ化されている次のコードを検討してください。

#!/usr/bin/bash

main(){
declare -i mycode=1
echo "Declared mycode:${mycode}"

{
  #command group
  echo "mycode:${mycode}"
  mycode=2
  echo "mycode:${mycode}"
} 2>&1

echo "mycode:${mycode}"
}

main

出力は次のとおりです

Declared mycode:1
mycode:1
mycode:2
mycode:2

コマンドグループ出力をログファイルとSTDOUTとしてキャプチャする必要があるため、次のようにteeを追加します。

#!/usr/bin/bash

main(){
declare -i mycode=1
echo "Declared mycode:${mycode}"

{
  #command group
  echo "mycode:${mycode}"
  mycode=2
  echo "mycode:${mycode}"
} 2>&1 | tee ~/log.log

 echo "mycode:${mycode}"
}

main

ただし、出力は次のようになります。

Declared mycode:1
mycode:1
mycode:2
mycode:1

だから価値は私のコードtee を使用すると、tee の左側がサブシェルで実行されるため、外部スコープでは変数が 2 に設定されません。様々な理由で私に必要私のコードグローバルスコープで定義されているため、サブシェルの使用を避ける必要があります。

サブシェルなしでteeの動作を実装して出力をSTDOUTおよびログファイルにストリーミングするにはどうすればよいですか?

答え1

この問題を解決する1つの方法は、パイプコネクタを直接実装することです。

#!/bin/bash

# Initialisation
mycode=1

# Tidy up
trap 'ss=$?; [ -n "$tmpd" ] && [ -d "$tmpd" ] && rm -rf "$tmpd"; exit $ss' 1 2 15

# Unique temporary directory
tmpd=$(mktemp --directory "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX")

# Create pipe
pipe="$tmpd/pipe"
mknod "$pipe" p

# Output
tee <"$pipe" "$HOME/log.log" &

# Subprocess
{
    echo "mycode:${mycode}"

    mycode=2
    echo "mycode:${mycode}"

} >"$pipe" 2>&1

# Destroy temporary, including pipe
wait
rm -rf "$tmpd"

# Done
echo "final mycode:${mycode}"

出力

mycode:1
mycode:2
final mycode:2

返品cat ~/log.log

mycode:1
mycode:2

答え2

ログファイルで達成したい目的に応じて、記述子#3に追加できます。 (記憶する標準出力1位標準エラー#3です。 )

#!/bin/bash

# Initialisation
mycode=1

# Attach fd3 to the logfile and stdout
exec 3> >(tee "$HOME/log.log" >&1)

# Demonstrations
echo this is to stdout
echo this is to stderr >&2
echo this is to logfile and stdout >&3

# Subprocess
{
    echo "mycode:${mycode}"

    mycode=2
    echo "mycode:${mycode}"

} 2>&1 1>&3

# Done
echo "final mycode:${mycode}"
sleep 0.25

このアプローチの1つの利点は、ファイルディスクリプタ3にリダイレクトするだけで、どこからでもログファイルに簡単に書き込むことができることです(上記の「デモ」コードブロックを参照)。

欠点はtee非同期で実行されるため、出力が誤ってインターリーブされる可能性があることです。究極の目標は、出力の作成を完了sleep 0.25する時間を許可することです。tee機能をどのように使用するかに応じて、インターリーブが実際の問題になる可能性があります。

出力例:

this is to stdout
this is to stderr
final mycode:2
this is to logfile and stdout
mycode:1
mycode:2

ログファイル(cat "$HOME/log.log"):

this is to logfile and stdout
mycode:1
mycode:2

関連情報