パイプラインでSTD {OUT、ERR}を複数回交換する

パイプラインでSTD {OUT、ERR}を複数回交換する

に基づいてこの回答、ファイル記述子 1 と 2 を交換するために、以下を作成しました。

swap12:

#!/bin/bash
"$@" 3>&1 1>&2 2>&3 3>&-

その後、パイプラインでSTDERRを操作できます。たとえば、次のようになります。

$ swap12 ls -ld /tmp /ooooooo | tr o X
ls: cannXt access '/XXXXXXX': NX such file Xr directXry
drwxrwxrwt 19 root root 1400 Jul  1 17:14 /tmp

ただし、FDを数回交換しても機能しません。

$ swap12 ls -ld /tmp /ooooooo | swap12 tr o X | tr o Z
ls: cannXt access '/XXXXXXX': NX such file Xr directXry
drwxrwxrwt 19 root root 1400 Jul  1 17:14 /tmp

上記では、2番目はswap12STDOUTとSTDRRを交換することを期待しているため、2番目は元のSTDOUTで動作しますtrls私は次を見るのを楽しみにしています:

$ swap12 ls -ld /tmp /ooooooo | swap12 tr o X | tr o Z
ls: cannXt access '/XXXXXXX': NX such file Xr directXry
drwxrwxrwt 19 rZZt rZZt 1400 Jul  1 17:14 /tmp

私が望むことをどのように達成できますか?

私の問題は、サブシェルでファイル記述子を変更することによって発生したようです。グローバルエイリアスとしてzsh実装すると利点がありますかalias -g? (しかしbash実際にはどんな姿なのでしょうか?)

答え1

通常、stderr端末に直接移動してstdoutパイプを入力します。

          ls stdout -->
ls -ld /tmp /ooooooo | tr o X
 |
 v ls stderr (to terminal)

交換したら、stdoutパイプではなく端末に移動します。

                 ls stderr -->
swap12 ls -ld /tmp /ooooooo | tr o X
        |
        v ls stdout

/交換は以前にパイプからリダイレクトされていたため、いかなるstdout方法でも結果は含まれません。stderrtrstderrls

                 ls stderr -->   tr stderr -->
swap12 ls -ld /tmp /ooooooo | swap12 tr o X | tr o Z
        |                             |
        v ls stdout                   v tr stdout

stdoutstderrを別々に処理するには、lsプロセス置換を使用できます(BashとZshで動作する必要があります)。

$ ls -ld /tmp /ooooooo 2> >(tr o X)  > >(tr o Z) 
ls: cannXt access '/XXXXXXX': NX such file Xr directXry
drwxrwxrwt 25 rZZt rZZt 4096 Jul  1 14:40 /tmp/

答え2

パイプはls.stderrに接続されていますtr1.stdin。その後、tr2に交換してtr1.stdoutパイプtr1.stderrしてsがないことを確認するので、何もしないでください。tr1.stderrtr2.stdino

2番目はswap12最初をキャンセルしてはいけません。

これをするつもりですか./swap12 ./swap12 ls -ld /tmp /ooooooo | tr o X?これによりスワップがキャンセルされます。

関連情報