コマンドラインからパイピングせずにティーを使用するようにbashスクリプトを強制する


20

大量の出力を持つbashスクリプトがあり、そのスクリプトを変更して(新しいスクリプトを作成しないで)、すべての出力をファイルにコピーしたいと思います。

スクリプトscript.shがあります:

#!/bin/bash
init
do_something_that_outputs_stuff_to_STDOUT
launch_applications_that_output_to_STDOUT
fini

そして、毎回入力することなく、STDOUTのファイルをscript.logファイルにコピーしたいと思います./script.sh | tee script.log

ありがとう、トム


これを前に言っていないのは残念ですが、スクリプトがかなり長いため、簡単な解決策を探しています。追記| 各行へのティーは少し多すぎます。
トム

回答:


15

デニスの非常にシンプルなワンライナーを機能させることができなかったので、ここにもっと複雑な方法があります。私は彼の最初を試してみます。

前述のように、execを使用して、スクリプト全体の標準エラーと標準出力をリダイレクトできます。そのように:
exec > $LOGFILE 2>&1 これはすべてのstderrとstdoutを$ LOGFILEに出力します。

これで、これをコンソールとログファイルに表示したいので、execが書き込み、teeが読み取りを行うための名前付きパイプも使用する必要があります。
(デニスのワンライナーは技術的にもこれを行いますが、明らかに異なる方法です)パイプ自体はで作成されmkfifo $PIPEFILEます。次に、以下を実行します。

#Tからログファイルへの書き込みを開始しますが、名前付きパイプからその入力をプルします。
tee $ LOGFILE <$ PIPEFILE&

#待機コマンドのティーのプロセスIDをキャプチャします。
TEEPID = $!

#残りのstderrとstdoutを名前付きパイプにリダイレクトします。
exec> $ PIPEFILE 2>&1

echo "ここにコマンドを作成します"
echo "彼らの標準出力はすべて破壊されるでしょう。"
echo "標準エラーもそうです">&2

#stderrおよびstdoutファイル記述子を閉じます。
exec 1>&-2>&-

#パイプのもう一方の端が閉じたので、ティーが終了するのを待ちます。
$ TEEPIDを待つ

徹底したい場合は、スクリプトの開始時と終了時に名前付きパイプファイルを作成および破棄できます。

記録のために、私はランダムな男の非常に有益なブログ投稿からこれのほとんどを集めました:(アーカイブされたバージョン


これはcygwinでは機能しないようです。:-(
docwhat

この投稿は教育の良い仕事をしています。どうもありがとうございました。
フェリペアルバレス14年

27

これをスクリプトの先頭に追加するだけです:

exec > >(tee -ia script.log)

これにより、stdoutに送信されたすべての出力がファイルscript.logに追加され、以前の内容がそのまま残ります。スクリプトを実行するたびに新しく起動する場合は、rm script.logそのexecコマンドの直前に追加する-ateeコマンドから削除します。

この-iオプションによりtee、割り込み信号が無視されtee、より完全な出力セットを取得できる場合があります。

この行を追加して、すべてのエラーも(別のファイルで)キャッチします。

exec 2> >(tee -ia scripterr.out)

複数の>シンボル間のスペースは重要です。


非常に興味深いソリューション。
チャフィンク

2
これは、私が投稿したすべてのがらくたに比べて、本当にエレガントな方法です。しかし、これらの2行を含むスクリプトを作成すると、ハングし、正常に終了しません。
クリストファーカレル


GNU bash、バージョン3.2.25(1)、RHEL5.3インストールの一部として。これは公式リポジトリの最新バージョンのようです。
クリストファーカレル

Bash 3.2.49(23)-releaseのcygwinで試してみたところ、ファイル記述子エラーが発生しました。ただし、Ubuntu 9.10のBash 4.0.33(1)-releaseで作業しているため、Bash 4の問題かもしれません。
追って通知があるまで一時停止します。

6

これは、以前にデニスウィリアムソンが投稿した回答を組み合わせたバージョンです。errとstdの両方をscript.logに正しい順序で追加します。

スクリプトの先頭に次の行を追加します。

exec > >(tee -a script.log) 2>&1

>記号間のスペースに注意してください。GNU bashバージョン3.2.25(1)-release(x86_64-redhat-linux-gnu)で動作します


5

私は別のアプローチがこのようなものだと思う:

#!/bin/bash

# start grouping at the top
{ 
    # your script goes here
    do_something_that_outputs_stuff_to_STDOUT
    launch_applications_that_output_to_STDOUT

# and at the bottom, redirect everything from the grouped commands
} 2>&1 | tee script.log 

3

出力のコピーが必要な場合は、次のtee方法を使用できます。

  #!/bin/bash
  init
  do_something_that_outputs_stuff_to_STDOUT | tee script.log
  launch_applications_that_output_to_STDOUT | tee -a script.log
  fini

ただし、これはscript.logにstdoutのみを記録します。stderrとstdoutの両方がリダイレクトされることを確認したい場合は、次を使用します。

  #!/bin/bash
  init
  do_something_that_outputs_stuff_to_STDOUT 2>&1 | tee script.log
  launch_applications_that_output_to_STDOUT 2>&1 | tee -a script.log
  fini

少し機能を追加することで、少し良くすることもできます。

  #!/bin/bash

  LOGFILE="script.log"
  # Wipe LOGFILE if you don't want to add to it at each run
  rm -f "$LOGFILE"

  function logcmd() {
        local cmd="$1" logfile=${LOGFILE:-script.log} # Use default value if unset earlier

        # Launch command, redirect stderr to stdout and append to $logfile
        eval '$cmd' 2>&1 | tee -a "$logfile"
  }

  init
  logcmd "do_something_that_outputs_stuff_to_STDOUT"
  logcmd "launch_applications_that_output_to_STDOUT"
  fini

いい答えです。彼が本当にstdoutだけを気にしているのなら、私はそのままに2>&1してtにパイプします。
DaveParillo

それは本当です、イゴールからの前の答えがそれをリダイレクトすることを気にし、それが良いアイデアだと思ったので、私はstderrを含めました。
チャフィンク

1

これを使用するだけです:

script logfile.txt
your script or command here

これにより、すべてがそのログに出力され、すべてが出力され、画面に表示されます。FULL出力が必要な場合、これがその方法です。

怠けている場合は、スクリプトを再生できます。


scriptパッケージであることに注意してください。sudo apt-get install scriptDebian フレーバーのディストリビューションにインストールするために、さらにscript -ac 'command opts' ~/Documents/some_log.script端末内で次のような方法でレビューできますstrings ~/Documents/some_log.script | moreリジェクト /ビューのより洗練された方法を可能にするために注入するstringsもののいくつかを事前にサニタイズする簡単方法である。それ以外の場合は、@ Phishyという堅実な答えです。なぜなら、インタラクティブなものも保存するからです。script script
S0AndS0

0
#!/bin/bash
init
do_something_that_outputs_stuff_to_STDOUT > script.log 2>&1
launch_applications_that_output_to_STDOUT >> script.log 2>&1
fini

この仕組みの詳細については、http//www.xaprb.com/blog/2006/06/06/what-does-devnull-21-mean/をご覧ください。


1
Igorの回答の2行目に2番目の>を追加して、最初の行に書き込まれたログを消去しないようにしました。
ダグ・ハリス

1
彼はコピーが欲しいので、を使用する必要がありますtee
チャフィンク

@Raphink:そうです:)
トム
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.