パイプが続く入れ子になったプロセスの置換: 「無効なファイル記述子」

パイプが続く入れ子になったプロセスの置換: 「無効なファイル記述子」

混乱したエラーが発生しましたが、よりよく理解したいと思います。この問題は「ラッパー」シェル関数(以下の説明)の存在を必要とするようです。 (投稿の末尾に私の問題についてより具体的に説明しました。)

このエラーを再現するために私が思いついた最も簡単なコードは、次のスクリプトにあります。 (スクリプトは確かに人為的で愚かですが、最初のエラーが発生する現実はこのようなデモに比べて複雑すぎます。)

# create an input file
cat <<EOF > demo.txt
a
b
c
EOF

# create a "wrapper shell function" for /usr/bin/join
my_join_fn () {
  /usr/bin/join "$@"
}
cat <(my_join_fn  <(cat demo.txt) <(cat demo.txt))
cat <(my_join_fn  <(cat demo.txt) <(cat demo.txt)) | head -1

# create a "wrapper shell function" for /usr/local/bin/gjoin, a port of
# GNU's join function for OS X
my_gjoin_fn () {
  /usr/local/bin/gjoin "$@"
}
cat <(my_gjoin_fn <(cat demo.txt) <(cat demo.txt))
cat <(my_gjoin_fn <(cat demo.txt) <(cat demo.txt)) | head -1

# show the version of zsh
$SHELL --version

誰かがこのスクリプトをソースとして使用すると(zsh)正常に終了し、次の(正しい)出力が生成されます。

% source demo.sh
a
b
c
a
a
b
c
a
zsh 5.0.2 (x86_64-apple-darwin11.4.2)

しかし、後でもう一度実行するとコマンドラインから直接、で終わるスクリプトの2行のうちの1つでエラーが| head -1発生しますbad file descriptor

% cat <(my_join_fn  <(cat demo.txt) <(cat demo.txt)) | head -1
join: /dev/fd/11: Bad file descriptor
% cat <(my_gjoin_fn <(cat demo.txt) <(cat demo.txt)) | head -1
/usr/local/bin/gjoin: /dev/fd/11: Bad file descriptor

これは、コマンドラインから直接実行するときにエラーが発生するスクリプトの唯一の2行です。

出力結果からわかるように、$SHELL --version上記の結果はOS Xで得られたものですが、Linuxでも同様のテストを実行したときに同様の結果が得られました。

% cat <(my_join_fn  <(cat demo.txt) <(cat demo.txt)) | head -1
/usr/bin/join: /proc/self/fd/11: No such file or directory
% $SHELL --version
zsh 4.3.10 (x86_64-unknown-linux-gnu)

bash(OS XまたはLinux)ではこのエラーを再現できません。zshこれにより、このバグが 。

だから解決策を探したいです。私の質問は次のとおりです

my_gjoin_fnこのエラーを回避するには、ラッピングシェル関数の定義をどのように修正する必要がありますか?

(実際の対応は、my_gjoin_fnフラグが呼び出しに含まれることを除いて、上記のものとほぼ同じですgjoin

my_gjoin_fn () {
  /usr/local/bin/gjoin -t$'\t' "$@"
}

これを使用してシェル関数をラップします。いつもだから私はそれを「保存」したいと思いました。 )

編集する:

| head -1| head -10コマンドの終わりを、、、| catなどに置き換えても| tee /dev/nullエラーがまだ存在します。| :たとえば、

% cat <(my_join_fn  <(cat demo.txt) <(cat demo.txt)) | cat
/usr/bin/join: /proc/self/fd/11: No such file or directory

また、ls -l /proc/self/fdmswが提案したように追加すると、次の結果が得られます。

% cat <(ls -l /proc/self/fd; my_join_fn  <(cat demo.txt) <(cat demo.txt)) | cat
total 0
lrwx------ 1 jones jones 64 Aug 21 12:29 0 -> /dev/pts/18
l-wx------ 1 jones jones 64 Aug 21 12:29 1 -> pipe:[312539706]
lrwx------ 1 jones jones 64 Aug 21 12:29 2 -> /dev/pts/18
lr-x------ 1 jones jones 64 Aug 21 12:29 3 -> /proc/23849/fd
/usr/bin/join: /proc/self/fd/11: No such file or directory

...それは意味がありません。他にも多くの情報を提供できます。 FWIW、ls -l /proc/self/fd私が入るかzsh出るかbash、またFWIW、ls -l /proc/self/fd単独で実行したときの出力は次のとおりです。

% ls -l /proc/self/fd
total 0
lrwx------ 1 jones jones 64 Aug 21 12:32 0 -> /dev/pts/18
lrwx------ 1 jones jones 64 Aug 21 12:32 1 -> /dev/pts/18
lrwx------ 1 jones jones 64 Aug 21 12:32 2 -> /dev/pts/18
lr-x------ 1 jones jones 64 Aug 21 12:32 3 -> /proc/5246/fd

ベストアンサー1

で動作を再現できましたzsh 4.3.10 (i686-pc-linux-gnu)

% cat <(funjoin  <(cat demo) <(cat demo)) | head -1 
join: /proc/self/fd/11: No such file or directory

私はマニュアルを掘り下げ、この問題に最も近いのがProcess Substitution in man zshexpnand MULTIOS in Chaptersであることを発見しましたman zshmisc

両方の章は、コマンド部分に中かっこを入れることに関連する解決策を提案します。

頑張った

% { cat <(funjoin  <(cat demo) <(cat demo)) } | head -1
1

効果がある

{ }zshの意味をよく理解できません。マニュアルでは、単に命令のリストとして説明します。私はこのMULTIOSが何をしているのか完全には理解していません。有効または無効にしても、あまり差がないようです。

関数本体の内部を含む他の場所に中かっこを配置しようとしましたが、funjoin正しく機能する唯一の場所は外部ですcat

おすすめ記事