shシェル:出力をスクリプト内の端末とファイルにリダイレクトする

shシェル:出力をスクリプト内の端末とファイルにリダイレクトする

stdoutとstderrをスクリプト内からファイルと端末にリダイレクトする方法。

#!/bin/bash

LOG_FILE="/tmp/abc.log"

exec &> >(tee -a $LOG_FILE)

echo "Start"
echo "Hi" 1>&2 
echo "End"

上記のスクリプトが見つかりました。ただし、このスクリプトはbashでのみ機能します。 sh シェルを使用すると、次のエラーが発生します。

./abc.sh: 5: Syntax error: redirection unexpected (expecting word)

shシェルとbashシェルで使用できるスクリプトが必要です。

ベストアンサー1

はい、&>演算子bash(現在サポートされており、zsh常に同じ機能をzsh持つ)と演算子(現在およびサポートされています)はどちらも演算子ではありません。引用符のない$ LOG_FILE、ここでは明らかに分割+globを使用してzsh構文にしたくありません(この方法ではありますが、分割+globが引用符のない拡張で暗黙的に実行しない唯一のシェルです)。>&csh>(...)kshzshbashshzshexec >&1 > $LOG_FILE 2>&1

構文的には、次のようにするshことができます。

#! /bin/sh -
LOG_FILE="/tmp/abc.log"

{

  # your script here


} 2>&1 | tee -- "$LOG_FILE"

またはすべてを関数に入れてください:

#! /bin/sh -
LOG_FILE="/tmp/abc.log"

main() {

  # your script here


}

main "$@" 2>&1 | tee -- "$LOG_FILE"

それにもかかわらず、このアプローチとzsh-styleアプローチの両方は、標準出力で開かれた同じリソースにエラーメッセージを出力します。したがって、誰かがこれを行うと、空でyour-script > out 2> err正常な出力とエラーが含まれます。errout

出力とエラーの元の宛先を保存するには、次のようにします。

{
  {
    main "$@" 3>&- | tee -a -- "$LOG_FILE" >&3 3>&-
  } 2>&1 | tee -a -- "$LOG_FILE" >&2 3>&-
} 3> "$LOG_FILE" 3>&1

(検証されていません)。

また、セキュリティの観点からは、グローバルに書き込み可能なディレクトリに固定された名前のファイルを使用するのは/tmp悪い習慣です。他のユーザーが同じ名前の悪意のあるシンボリックリンクを配置する可能性があるため、そのリンクが指すポイントを上書きする可能性があります。文書。

おすすめ記事