シェルスクリプトで画面とファイルにテキストを出力する方法は?

シェルスクリプトで画面とファイルにテキストを出力する方法は?

現在、次のようにログファイルにメッセージを記録するシェルスクリプトがあります。

log_file="/some/dir/log_file.log"
echo "some text" >> $log_file
do_some_command
echo "more text" >> $log_file
do_other_command

このスクリプトを実行すると、画面に何も出力されず、パテを介してサーバーに接続されているため、スクリプトの実行を終了できず、したいので、別の接続を開いて「tail -f log_file_path.log」を実行する必要があります。リアルタイムで出力を見ることができます。

明らかに私が望むのは、テキストメッセージを画面とファイルに印刷することですが、2行ではなく1行でやりたいと思います。そのうちの1つはファイルにリダイレクトされません。

この目標を達成する方法は?

答え1

これは働きます:

command | tee -a "$log_file"

tee入力をファイルに保存し(-a上書きの代わりに追加を使用)、入力を標準出力にコピーします。

コマンドは現在非対話型で実行中であることを検出できるため、動作が変更される可能性があります。最も一般的な副作用は、カラー出力が無効になることです。このような場合(ANSIカラーで区切られた出力が必要な場合)、コマンド文書を確認して強制的に対話型の動作に戻す方法があるかどうかを確認する必要がありますgrep --color=always返品less --RAW-CONTROL-CHARS "$log_file"エスケープコードリテラルを中断せずに読み取るために使用するエスケープコードが含まれています。また、ログファイルの内容を作成する方法はありません。その他上記のコマンドを実行したときに画面に印刷される内容は何ですか?したがって、画面上の色分けされた出力とログファイルに色以外の出力を持つことはできません。

答え2

こことのドキュメントを使用して、効率的でPOSIXフレンドリーなユニバーサルコレクタモデルに使用できます。

. 8<<-\IOHERE /proc/self/fd/8

command
fn() { declaration ; } <<WHATEVER
# though a nested heredoc might be finicky
# about stdin depending on shell
WHATEVER
cat -u ./stdout | ./works.as >> expect.ed
IOHERE

heredocを開くときに、IOHERE入力フラグを使用して、制限フラグのもう一方の端に遭遇するまで、入力を指定したファイル記述子にリダイレクトする必要があるというシグナルをシェルに送信します。私は周りを見ましたが、heredoc演算子で上記​​のようにリダイレクトされたfd番号を使用する例はあまりありません。しかし、その使用はPOSIX基本シェルコマンドガイドで明確に指定されていますが、そうです。ほとんどの人は単にstdinを指して撮影しましたが、私はこの方法でスクリプトレットを取得するとstdinが自由に保たれ、設定アプリケーションがI / Oパスブロックについて文句を言わないことを発見しました。

Heredocの内容は、ユーザーが指定したファイル記述子にストリーミングされ、これはシェルコードとして解釈されます。 。 /proc/self パスに問題がある場合は、/dev/fd/n または /proc/$$ を試してください。しかし、同じアプローチがパイプにも適用されます。

cat ./*.sh | . /dev/stdin

おそらく少なくとも見えるほど軽率な行動でしょう。もちろん、shを使って同じことをすることができますが。 。

とにかく、ご存知のように、私はまだあなたの質問に答えていません。しかし、考えると、heredocがすべてのコードを.にストリーミングするのと同じように、単一で簡単な終了点も提供します。

. 5<<EOIN /dev/fd/5 |\ 
    tee -a ./log.file | cat -u >$(tty)
script
more script
EOIN

したがって、heredocで実行されるすべてのコードのすべての端末標準出力は 。現在、stdoutの方向がわからないため、バッファリングされていないcat呼び出しを含めましたが、重複する可能性があり(ほぼ確実に作成されたとおり)、パイプがティーで終わることがあります。

2番目の例では、欠落しているバックスラッシュ引用符について疑問を提起することがあります。始める前にこのセクションを理解することが重要であり、それを使用する方法についていくつかのアイデアを得ることができます。引用されたheredoc制限子(これまではIOHEREとEOINを使用しました。最初にバックスラッシュで引用しましたが、「単一」または「二重」引用符も同じ目的で使用されます)はシェルが内容を書き込むことを許可しません。引用符のない修飾子は拡張のために内容を開いたままにします。これにより、区切り記号が 。ソースはドラマチックです。

. 3<<HD ${fdpath}/3
: \${vars=$(printf '${var%s=$((%s*2))},' `seq 1 100`)} 
HD
echo $vars
> 4,8,12… 
echo $var1 $var51
> 4 104

区切り文字の制約を引用しないので、シェルは結果ファイル記述子を 。これにより、本質的にコマンドは2回解析されます。これはとにかく拡張可能です。 $ varsパラメータ拡張をバックスラッシュしたため、シェルは最初のパスでその宣言を無視し、バックスラッシュのみを削除しました。したがって、全体のprintf拡張は最初のパスでnullと評価することができました。スクリプトは2番目のパスで取得されました。

この機能は、基本的に危険なevalシェル組み込み関数が提供できるものとまったく同じです。区別された文書から引用することは、evalでより扱いやすく、危険ではありません。慎重に計画しない限り、習慣的に「EOF」リミッターを参照するのが最善です。ちょうど言うよ。

編集:まあ、私はこれを振り返り、それが少し過度だったと思います。複数の出力を単一のパイプに接続するだけの最も簡単な方法は、次のものを使用することです。

{ or ( command ) list ; } | tee -a ea.sy >>pea.sy

中かっこは現在のシェルで何かを実行しようとし、中かっこは自動的に分離されます。それにもかかわらず、誰もが言うように、少なくとも私の考えでは、.Heredocソリューションはより価値のある情報です。特に、シェルが実際にどのように機能するかを理解したい場合は、さらにそうです。

楽しくお過ごしください!

答え3

teeステートメントを使用して実行したくない場合は、次のようにします。

#!/bin/bash
# A Shell subroutine to echo to screen and a log file

log_file_name="/some/dir/log_file.log"

echolog()
(
    echo "$@"
    echo "$@" >> $log_file_name
)


echo "no need to log this"
echolog "some important text that needs logging"

これで、元のスクリプトから「echo」をログファイルに出力したい「echolog」に変更できます。

答え4

私はMacosで使用しています。 Linuxシステムでも動作します。

command > /dev/stdin > mylog.log

関連情報