web-dev-qa-db-ja.com

stderrをファイルにリダイレクトする方法

Nohupを使用して、バックグラウンドで実行するコマンドを配置すると、コンテンツの一部がターミナルに表示されます。

cp: error reading ‘/mnt/tt/file.txt’: Input/output error
cp: failed to extend ‘/mnt/tt/file.txt’: Input/output error

そのコンテンツをファイルに保存したい。

295
André M. Faria

Linux(および他のOS)には、標準出力(stdout)と標準エラー(stderr)の2つのメイン出力ストリームがあります。表示するようなエラーメッセージは、標準エラーに出力されます。従来のリダイレクト演算子(command > file)は標準出力のみをリダイレクトするため、端末には標準エラーが引き続き表示されます。 stderrもリダイレクトするには、いくつかの選択肢があります。

  1. Stdoutを1つのファイルにリダイレクトし、stderrを別のファイルにリダイレクトします。

    command > out 2>error
    
  2. Stderrをstdout(&1)にリダイレクトしてから、stdoutをファイルにリダイレクトします。

    command >out 2>&1
    
  3. 両方をファイルにリダイレクトします(これはすべてのシェルでサポートされているわけではありません。たとえば、bashおよびzshはサポートしていますが、shおよびkshはサポートしていません)

    command &> out
    

さまざまな制御およびリダイレクト演算子の詳細については、 here を参照してください。

520
terdon

最初に注意することは、目的とシェルに応じていくつかの方法があるため、複数の側面を少し理解する必要があることです。さらに、timestraceなどの特定のコマンドは、デフォルトでstderrに出力を書き込み、そのコマンドに固有のリダイレクト方法を提供する場合と提供しない場合があります。

リダイレクトの背後にある基本的な理論は、Shellによって生成されたプロセス(シェル組み込みではなく外部コマンドであると仮定)はfork()およびexecve() syscallsを介して作成され、その前に別のsyscall dup2()は、execve()が発生する前に必要なリダイレクトを実行します。その意味で、リダイレクトは親シェルから継承されます。 m&>nおよびm>n.txtは、open()およびdup2() syscallの実行方法をシェルに通知します( 入力リダイレクトの仕組みリダイレクトとパイプの違いは何ですか 、および 出力リダイレクトの意味と正確な意味

シェルリダイレクト

最も一般的なのは、 dash2>にシンボリックリンクされている)やbashなど、 Bourneのようなシェル/bin/shを介したものです。最初はデフォルトのPOSIX準拠のシェルで、もう1つはほとんどのユーザーが対話型セッションに使用するものです。構文と機能は異なりますが、幸いなことにエラーストリームリダイレクトは同じように機能します(&>非標準のものを除く)。 cshとその派生物の場合、stderrリダイレクト そこではまったく機能しません。

2>パートに戻りましょう。注目すべき2つの重要な点:>はリダイレクト演算子を意味します。ここではファイルを開き、2 integerはstderrファイル記述子を表します。実際、これはまさにシェル言語のPOSIX標準が セクション2.7 でリダイレクトを定義する方法です。

[n]redir-op Word

単純な>リダイレクトの場合、1整数はstdoutに含まれます。つまり、echo Hello World > /dev/nullecho Hello World 1>/dev/nullと同じです。整数またはリダイレクト演算子は引用符で囲まれないことに注意してください。そうしないと、シェルはそれらをそのように認識せず、代わりにテキストのリテラル文字列として扱います。間隔に関しては、整数がリダイレクト演算子のすぐ隣にあることが重要ですが、ファイルはリダイレクト演算子の隣でもそうでなくてもかまいません。つまり、command 2>/dev/nullcommand 2> /dev/nullは問題なく動作します。

シェルの典型的なコマンドのやや単純化された構文は次のようになります

 command [arg1] [arg2]  2> /dev/null

ここでのコツは、リダイレクトがどこにでも現れる可能性があることです。つまり、2> command [arg1]command 2> [arg1]の両方が有効です。 bash Shellには、stdoutストリームとstderrストリームの両方を同時にリダイレクトする&>の方法がありますが、これもまたbash固有であり、スクリプトの移植性を求めている場合は機能しない可能性があります。 buntu Wiki および &>と2>&1の違いは何ですか も参照してください。

注:>リダイレクト演算子はファイルを切り捨て、ファイルが存在する場合、上書きします。 2>>は、stderrをファイルに追加するために使用できます。

お気づきかもしれませんが、>は単一のコマンドを意味します。スクリプトの場合、myscript.sh 2> /dev/nullのように外部からスクリプト全体のstderrストリームをリダイレクトするか、 exec built-in を使用できます。組み込みのexecには、いわば、対話的またはスクリプト経由で、シェルセッション全体のストリームを再配線する機能があります。何かのようなもの

#!/bin/sh
exec 2> ./my_log_file.txt
stat /etc/non_existing_file

この例では、ログファイルにstat: cannot stat '/etc/non_existing_file': No such file or directoryと表示されます。

さらに別の方法は、関数を使用することです。 kopciuszek の回答で述べたように、リダイレクトを既に付加した関数宣言を書くことができます。

some_function(){
    command1
    command2
} 2> my_log_file.txt

Stderrに排他的に書き込むコマンド

timestraceなどのコマンドは、デフォルトでそれらの出力をstderrに書き込みます。 timeコマンドの場合、唯一の実行可能な代替手段は、コマンド全体の出力をリダイレクトすることです。

time echo foo 2>&1 > file.txt

あるいは、出力を分離する場合は、同期リストまたはサブシェルをリダイレクトできます( related post に示すように)。

{ time sleep 1 2> sleep.stderr ; } 2> time.txt

stracedialogなどの他のコマンドは、stderrをリダイレクトする手段を提供します。 straceには、出力を書き込むファイル名を指定できる-o <filename.txt>オプションがあります。 straceが見る各サブプロセスのテキストファイルを書くためのオプションもあります。 dialogコマンドは、テキストユーザーインターフェイスをstdoutに書き込みますが、stderrに出力します。したがって、 その出力を変数に保存しますvar=$(...)とパイプラインはstderrのみを受け取るため)には、ファイルをスワップする必要があります記述子

result=$(dialog --inputbox test 0 0 2>&1 1>/dev/tty);

しかし、さらに、--output-fdフラグがあり、これも利用できます。名前付きパイプのメソッドもあります。何が起こっているかを完全に説明するには、dialogコマンドに関するリンクされた投稿を読むことをお勧めします。

15