web-dev-qa-db-ja.com

shコマンド:exec 2>&1

このコマンドは何をしますか?

exec 2>&1 
47
valodzka

技術的に言えば、stderrをstdoutに複製またはコピーします。

通常、これを実行するためにEXECは必要ありません。 execとファイル記述子のより一般的な使用法は、ファイルを未使用のファイル記述子に割り当てることを示すことです。

exec 35 <my_input

ところで、ファイルにパイピングするときの宣言のシーケンスが重要であることを忘れないでください。

ls > mydirlist 2>&1

これは、stdoutとstderrの両方をファイルmydirlistに送るために機能しますが、コマンド

ls 2>&1 > mydirlist

stderrはmydirlistにリダイレクトされる前にstdoutのコピーが作成されたため、stderrではなくstdoutのみをmydirlistにファイルします。

編集:これは、シェルが左から右にスキャンする方法です。したがって、「stdoutをmydirlistに送信する」と言う前に、「stderrをstdoutにコピーする」という2番目のものを読んでください。次に、「mydirlistファイルにstdoutを送信する」という最初のメッセージを読んでから、「設定したstdoutにstderrを複製する」と言います。知っている。それは完全に直感的ではありません!

37
Rob Wells

私が「2>&1」が何をするかで見たより良い記事の1つは、 Bash One-Liners Explained、Part III:All about redirections です。

しかし、この質問に関する現在の答えが提供していないのは、単純な「exec」の後にこれをしたい理由です。 execコマンドのbashのマニュアルページで説明されているように、「コマンドが指定されていない場合、リダイレクトは現在のシェルで有効になります」。

私はout-and-err.pyと呼ばれる単純なスクリプトを書きました。このスクリプトは、出力の行をstdoutに書き込み、別の行をstderrに書き込みます。

#!/usr/bin/python
import sys
sys.stdout.write('this is stdout.\n')
sys.stderr.write('this is stderr.\n')

そして、「exec 2>&1」を使用して、out-and-err.shというシェルスクリプトでそれをラップしました。

#!/bin/bash
exec 2>&1
./out-and-err.py

pythonスクリプトだけを実行すると、stdoutとstderrは分離されます。

$ ./out-and-err.py 1> out 2> err
$ cat out
this is stdout.
$ cat err
the is stderr.

しかし、Shellスクリプトを実行すると、execがすべての後のstderrを処理することがわかります。

$ ./out-and-err.sh 1> out 2> err
$ cat out
this is stdout.
this is stderr.
$ cat err
$

ラッピングシェルスクリプトが1つだけではなくpythonコマンドを実行し、すべての出力をstdoutに結合する必要がある場合、 "exec 2>&1"を実行すると簡単になります。

32
Brian Taylor

標準エラーを標準出力に結び付けます

2はstderrであり、1はstdoutです。プログラムを実行すると、stdoutで通常の出力が得られますが、エラーや警告は通常stderrに送られます。たとえば、すべての出力をファイルにパイプする場合、最初にstderrとstdoutを2>&1で結合すると便利です。

13
Charles Ma

@cmaが言ったように、stderrをstdoutに置きます。この動作が必要な理由は、grepまたはその他のユーティリティを使用して、stderrにのみ表示される出力をキャプチャするためです。または、後で処理するために、stderrを含むすべての出力をファイルに保存することもできます。

2
Mark Rushakoff

最近、私もこの問題に嫌気がさしていましたが、今はそこから飛び出しました。したがって、CLIで_exec 1>&2_を入力した後に何が起こるかを説明させてください。

問題を少しずつ破壊したいので、知識がわかっている場合は、時間を節約するためにそれをざっと読んでください。

  • execとは:

execは、Linuxの組み込みコマンドです。サブシェルプロセスをフォークするだけの従来のコマンドとは異なり、execは現在のシェルプロセスを変更できます。

  • I/Oリダイレクトとは:リダイレクトはLinuxの機能です。これにより、標準の入力/出力デバイスを変更できます。 Linuxには、デフォルトで3つのファイル記述子があります。 _Handle Name Description 0 stdin Standard input 1 stdout Standard output 2 stderr Standard error_

  • 例を見てみましょう:

    1. 新しいターミナルを開く
    2. TermianlプロセスプロセスIDを取得_$ pstree -p | grep 'term' | tr -d ' '_
    3. プロセスファイル記述子を確認してください。 _$ Sudo ls -l /proc/{pid}/fd_ bash $ pstree -p | grep -i 'terminal' | tr -d ' ' ||||-gnome-terminal-(6008)-+-bash(7641)-+-grep(8355) $ Sudo ls -l /proc/7641/fd total 0 lrwx------ 1 alopex alopex 64 Oct 27 19:39 0 -> /dev/pts/3 lrwx------ 1 alopex alopex 64 Oct 27 19:39 1 -> /dev/pts/3 lrwx------ 1 alopex alopex 64 Oct 27 19:39 2 -> /dev/pts/3 lrwx------ 1 alopex alopex 64 Oct 27 19:39 255 -> /dev/pts/3ご覧のとおり、lsはPID(6860)プロセスファイルをリストします。最初はすべて番号(0、1、2)で名前を付け、2番目はすべて/ dev/pts/3にファイルリンクをリンクします。これは、pts3にすべての標準入力/出力/エラーが表示されることを意味します。
    4. 標準出力を/ tmp/stdout _bash $ ls /tmp/stdout ls: cannot access '/tmp/stdout': No such file or directory $ exec 1>/tmp/stdout $ ls $ pwd $ echo "Are you ok" $_に変更します。その時点でコマンド出力は消えていました。
    5. 新しいターミナルを開いて、procファイル_bash $ Sudo ls -l /proc/7641/fd total 0 lrwx------ 1 alopex alopex 64 Oct 27 19:39 0 -> /dev/pts/3 lrwx------ 1 alopex alopex 64 Oct 27 19:39 1 -> /tmp/stdout lrwx------ 1 alopex alopex 64 Oct 27 19:39 2 -> /dev/pts/3 lrwx------ 1 alopex alopex 64 Oct 27 19:39 255 -> /dev/pts/3_を確認します。明らかに、1(ファイル記述子)がすでに/ tmp/stdoutへのリンクを変更していることがわかります。例外として、標準出力は/ tmp/stdoutに転送されます
    6. リダイレクトを復元します。 _bash $ exec 1>&2 $ cat /tmp/stdout a.sh /home/alopex Are you ok $ Sudo ls -l /proc/7641/fd total 0 lrwx------ 1 alopex alopex 64 Oct 27 19:39 0 -> /dev/pts/3 lrwx------ 1 alopex alopex 64 Oct 27 19:39 1 -> /dev/pts/3 lrwx------ 1 alopex alopex 64 Oct 27 19:39 2 -> /dev/pts/3 lrwx------ 1 alopex alopex 64 Oct 27 19:39 255 -> /dev/pts/3_繰り返しますが、1(ファイル記述子)は/ dev/pts/3にリンクしています。出力をもう一度見ることができます。
  • 概要:

  • _exec 1>&2_標準出力を作成--->標準エラー
0
Alopex

私が遭遇したexec 2>&1の非常に便利なアプリケーションの1つは、セミコロンで区切られたいくつかのコマンドのstderrstdoutをマージしたい場合です。私の特定の例は、複数のコマンドをpopenにPHP=に送信していたときに起こりました。促す:

$ echo hi ; yikes ; echo there
hi
-bash: yikes: command not found
there
$ 

次は、最後のstderrを除いて、stdoutechoをマージしません(yikesがエラーを引き起こすため、意味がありません):

echo hi ; yikes ; echo there 2>&1

次のように「ハードウェイ」でマージされた出力を取得できます。

echo hi 2>&1; yikes 2>&1; echo there 2>&1

execを使用すると、かなりクリーンでエラーが発生しにくくなります。

exec 2>&1 ; echo hi; echo yikes; echo there

セミコロンで区切られた3つのコマンドを実行した場合、ターミナルで表示されるのとまったく同じように、stdoutおよびstderr出力がうまくインターリーブされます。

0
drchuck