Bashブロックリダイレクトとパイプ

Bashブロックリダイレクトとパイプ

bashリダイレクトを学んでいます。以下のコードがls | grep foo | grep bar

#!/bin/bash                                                                     

{
    {
        ls | grep foo
    } 2>&1 1>&4 | grep bar
} 4>&1

これはfooと一致しますが、fooとbarとは一致しません。2>&1私はfd 1のパイプがfd 2にコピーされ、fd 1をstdoutにリセットするのでこれがうまくいくと思います。

中かっこ(コンテキスト)を維持しながらこのコードを変更できますか?削除すると2>&1 1>&4期待どおりに動作します。しかし、私は学びたい。

パイプの左側ではstdoutだけが必要だと思うので、パイプをfd 2にコピーしても、パイプの左側でfd 1だけを探します。

引用:https://wiki.bash-hackers.org/howto/redirection_tutorial#an_example

上記のリンクには、cmd1のfd 2がcmd3のfd 0を指す図があります。私は私の例を通してこれを確認しようとしています。

答え1

あなたの試み:

{
    {
        ls | grep foo # goes to stdout (fd 1)
    } 2>&1 1>&4 | grep bar  # at this level: 2 now points to where fd1 is pointing (stdout), and 1 is *then* directed to the new fd 4 (ie to stdin of the outside curly)
} 4>&1  ## at this shell 'level', a new fd 4 is now pointing to where 1 is pointing: stdout

:したがって、grepバーは{ls | grep foo}のstderrでのみ行われるため、空の標準入力では{ls | grep foo}のstderrが{ls grep foo} grep fooに移動します。 }.ファイル名は表示されません。このファイル名をfd 4に入力してください。

{
    {
        ls | grep foo
    } 2>&1 1>&4
} 4>&1 | grep bar

または

{
    {
        ls | grep foo
    } 2>&1 1>&4 | <&4 grep bar
} 4>&1

比較して...

注:内部コマンドのstderrもstdoutに移動するには、それを2番目の場所にコピーする必要があります。 1>&4 2>&1 [つまり、1 は fd 4 に移動し、2 は 1 の位置に移動します。今指していること、つまりfd 4と]

答え2

私が知る限り、次は本当です。

これ

{
    {
        ls | grep foo
    } 2>&1 1>&4 | grep bar
} 4>&1

等しい

(ls | grep foo 2>&1 1>&4 | grep bar) 4>&1

fd 4が/dev/pts/0で、1>&4のため、fd 1がパイプの代わりに同じ/dev/pts/0を持つようになるため、失敗します。

答え3

リダイレクトを通じてデータをコピーしたいと思いますか?teeあなたが学んでいる間、私はもう仕事を台無しにしません。

shellcheckコードの検査にも使用できます。ほとんどのエラーをすばやく見つけるのに役立ちます。

関連情報