次のコマンドの機能を実行する簡単な方法はありますか?
watch foo 2>/dev/null | tr ' ' '-'
strace foo 2>/dev/null | tr ' ' '-'
something_else foo 2>/dev/null | tr ' ' '-'
物事がどのように行動するべきかについての共有された期待はありますかsomething_else
?これらのコマンド(どのプログラムの出力がリダイレクトされるかなど)を明確にすることができるシェル構造はありますか?
答え1
コマンド自体はリダイレクトを処理しません。シェルがコマンドを実行する新しいプロセスを作成すると、シェルは指示に従ってIOを設定します。コマンド自体は実行されるので、気にする必要はありません。
あなたのsomething_else
コマンドは通常どおり出力をstdoutとstderrに送ります。
答え2
簡単に言うと:
some_elseがどのように機能するのかという共通の期待はありますか?
はい、常設命令です。シェルは2つのコマンドを理解していません。これはコマンドと引数です(command1 command2
たとえば、有効なバイナリの名前かもしれません)。/bin
これはcommand1
後でシェルではなくシステムコールを介して command2
実行されます。exec()
これらのコマンド(どのプログラムの出力がリダイレクトされるかなど)を明確にすることができるシェル構造はありますか?
いいえ、someting_else
特別な治療を受けません。前述のように、コマンドと引数以外の構造はありません。この問題に対する混乱は次のようなものにあるようです。両方 strace
シェルによって実行されると仮定しますが、foo
実際には親 - サブプロセスチェーンです。
シェルがコマンドとリダイレクトを処理する方法
Bourne(たとえば、、、bash
)dash
などksh
のシェルは、すべてコマンド解決方法についてPOSIXの規則に従います。POSIXの指定: ""単純なコマンド"は任意の順序でオプションの変数の割り当てとリダイレクトのシーケンスであり、オプションでワードとリダイレクトが続き、制御演算子で終了します。これはテーブルとして作成できます。
[VAR=foo BAR=baz] command1 [arg1, arg2...] [ n>m ]
一般的な規則は、ほとんどの非割り当て単語を保存するコマンドにリダイレクトが適用されることです。あなたの例ではstrace
コマンドですがfoo
引数ですstrace
。リダイレクトは引数ではなくコマンドに対してのみ機能します。つまり、シェルによって実行さstrace
れず、この場合は子プロセスによって実行されます。今回もパラメータ付きのコマンドとして扱われます。foo
strace
foo
strace
somethingelse
foo
ファイル記述子
組み込まれていないコマンドに関する限り、そのコマンドはシェルの子プロセスであり、子プロセスはシェルのファイル記述子を継承するため、通常はリダイレクトを管理しません。 「事前にパッケージ化された」宛先を受け取るので、strace
現時点では2>/dev/null
そうです。ファイル記述子2が実際に何であるかは気にしません(ソースコードレベルを積極的に確認しない限り)。strace
出力はまだファイル記述子2に書き込まれますが、シェルはそのファイル記述子を/dev/null
。
strace stat noexist 2>stracelog.txt
ファイル記述子は継承されるため、両方のエラーストリームでこのような操作を実行してstrace
同じstat
ファイルに移動する理由も説明されています。対照的に、一部のコマンドでは、ターゲットをオプションの1つとして明示的に指定できます。したがって、ファイルに出力のみがありますstrace -o tracelog.txt stat noexist 2>stracelog.txt
。ファイル記述子が継承されてもフラグはの属性であり、ファイル記述子が継承されても出力はコマンドによって管理されます。stat
stracelog.txt
-o
strace
これはまた少しヒントを提供します。理論的には、コマンドは「リダイレクト」することができます。つまり、ファイル記述子はシステムコールを介して既存のファイル記述子にコピーされますdup2()
。これはシェルで使用されるメカニズムとまったく同じですが、リダイレクトシンボルの用語>
タイプに関する限り、これはまだシェル制御下にあるため、親シェルによってのみ解釈できます。
なぜ2>/dev/nullですか?
通常、診断出力がに送信されることが知られていますstderr
。実際には、そのトピックに関する2つの素晴らしい記事がすでにあります。
watch
あなたの例の規則に従ってくださいstrace
。それがすべてです。2>/dev/null
そのようなコマンドの出力を隠すように指定する要件自体はありません。
たとえば、引数として渡されるコマンドのリダイレクトを実際に指定するには、strace
そのコマンドの周囲にシェルが必要です。例えば、
strace -f bash -c 'stat /etc/passwd nonexisting 2>/dev/null'
フラグを使用するときは注意してください-f
。コマンドに適用されたシステムコールを追跡することに焦点を当てると、stat
フラグなしではその呼び出しを見ることができないからです-f
。