質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

Q&A

解決済

2回答

2122閲覧

Bashのファイルディスクリプタを名前付きパイプのように使ってよいか

aachyee

総合スコア114

bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

0グッド

0クリップ

投稿2020/10/23 19:01

編集2020/10/23 19:08

Bashのファイルディスクリプタの使い方に関する質問です。
下記のコードのようにexecを使って何もしないコマンドとの入出力を介するファイルディスクリプタ(以下fd)を作成します。
このfdはmkfifoで作成する名前付きパイプのように使うことができたのですが、こういった使い方は正しい使い方なのでしょうか。
もし問題があるようでしたら、その理由を教えていただけないでしょうか。もっと賢い書き方がある場合でも構いません。
よろしくお願いいたします。

該当のソースコード

bash

1exec {fd}<> <(:) # or exec {fd}<> >(:) 2echo -e "0123456789\nABDEFGHIJKLMNOPQRSTUVWXYZ" >&${fd} 3read l <&${fd} 4echo $l # -> 0123456789 5read l <&${fd} 6echo $l # -> ABDEFGHIJKLMNOPQRSTUVWXYZ 7exec {fd}>&-

補足情報(FW/ツールのバージョンなど)

Bash version: 4.4.12
OS: Debian GNU/Linux 9

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

<(:)でFIFOが作成されて、それがファイルディスクリプターfdで、読み書きオープンされるので、間違いと言うことは無いと思います。

そのFIFOは、<(:)なのでexecコマンド実行中だけはファイルディスクリプター 0でも読み込みオープンされますが、exec終了と共にクローズされるはずです。

LinuxやWindows+WSLのbashだとお書きの通りの結果になりますが、Windows+MSYS2のbashだと手元の環境では/dev/fd/${fd}に対しての書き込み権が無くechoによる書き込みがエラーになります。chmod u+w /dev/fd/${fd}もエラー。
>(:)に変えると今度は読み込み権が無くなります。
うまく行く環境だと、読み書き権が付いているのですが。

bash

1mkfifo tmp-fifo 2exec {fd}<> tmp-fifo 3rm tmp-fifo #アンリンクして無名にする 4echo -e "0123456789\nABDEFGHIJKLMNOPQRSTUVWXYZ" >&${fd} 5以下同じ

だとMSYS2でもうまく行きますね。プロセス置換の実装に問題があるのかも知れません。

あと、質問のコードは一部$が抜けているので訂正しておいて下さい。

投稿2020/10/24 08:58

編集2020/10/25 02:22
otn

総合スコア84529

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

aachyee

2020/10/24 16:53

ご回答をありがとうございます。なるほど環境によって挙動が違うのは盲点でした。 コードで$が抜けているのはどこでしょうか?WSLのdebianでは特に異常は見られなかったのですが。
aachyee

2020/10/24 17:28

msys2をインストールしてmkfifoを使うコードやってみたところrmでフリーズ?して戻ってこないですね。
otn

2020/10/25 02:25

失礼しました。変数を使ってファイルディスクリプターの指定する際には$を書かないんですね。知りませんでした。 回答に exec ${fd}と書いていたので訂正しておきました。 > rmでフリーズ? 単にコマンドラインで、mkfifo → rm だとどうでしょう?
aachyee

2020/10/25 12:09 編集

mkfifo → rm なら問題無いですね。Windows 10 Home 2004なのですが、OSの違いが影響してるのかなぁ。 いずれにしても質問のような出力先(や入力元)が消えたり終了したパイプは使わないほうがいいですね。勉強になりました。クローズにします。
otn

2020/10/25 12:57

まあ、そのタイミングでrmするのは必要ではないので、後で消すでも良いと思います。
guest

0

ベストアンサー

正しいか正しくないかで言えば、「正しくない」だと思います。→ 訂正します
-- 最初の見解
なぜかというと、<(:) で作られるのは、無名のパイプの読み込み側の口で、それを <> で読み書き両用に使おうとしているからです。
※無名パイプは、読み込み・書き込みの2つの口が別々にできることになっているので、その方向性を違えて使った場合の保証は、多分どこにもされていない。

そういう意味で、双方向のパイプを使いたい場合は coproc を選ぶか、今回のような片方向の変則的な使い方の場合は無理にパイプにせずに $() や `` を使って出力をとりこんでおくか、そこら辺が妥当とは思います。

ただ、このアイデア自体は個人的には好きですね。考え付きませんでした。

--
以下訂正: Linuxならありな気がしてきました。

  • <> <(:) をする場合は、「無名パイプの読み込み側FDを読み書き両用でFDコピー」ではなく、「無名パイプ実体へのシンボリックリンク ( /dev/fd/数値 ) を読み書き両用で別途オープン」なので「読み込み側だから」という理由は不当
  • 明確にドキュメント化されてるかは分からないが、Linuxでは無名パイプはpipefsという内部的なファイルシステム上のfifoとして扱われるので、名前付きパイプと(ファイル名が明確に見える以外の)違いはない
  • 名前付きパイプ(fifo)を読み書き両用でオープンするのは、POSIX的には保証されていないが、Linuxでは動作する。( https://linuxjm.osdn.jp/html/LDP_man-pages/man7/fifo.7.html 参照 )

ということで、Linuxならテンポラリな名前付きパイプと同等、で良いと思います。

投稿2020/10/24 02:15

編集2020/10/24 10:09
angel_p_57

総合スコア1672

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

aachyee

2020/10/24 03:22

ご回答をありがとうございます。coprocの利用を検討してみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問