GNU/Linux >> Linux の 問題 >  >> Linux

一時ファイルの作成 vs プロセス置換 vs 変数展開?

<(cmd) ksh です 最近では zsh にもある機能 と bash プロセス置換と呼ばれる .

/dev/fd/n をサポートするシステムの場合 または /proc/self/fd/n 、パイプで実装され、そうでない場合は一時的な名前付きパイプで実装されます。いずれにせよ、これはプロセス間通信メカニズムであるパイプの形式です。

cmd1 <(cmd2)

記述可能 (通常のパイプを使用):

{ cmd2 4<&- | 3<&0 <&4 4<&- cmd1 /dev/fd/3; } 4<&0

または (名前付きパイプを使用):

mkfifo /tmp/named_pipe
cmd2 > /tmp/named_pipe & cmd1 /tmp/named_pipe

つまり、両方のコマンドが同時に開始され、パイプと通信します。通常は cmd2 | cmd1 を使用します そのためですが、プロセスの置換は通常、 cmd1 の場合に使用されます 標準入力からではなく、ファイル名からのみ入力を取得できます。または diff <(cmd1) <(cmd2) のように複数の入力が必要な場合 .

プロセス数、CPU 時間、メモリなどの一般的なもの以外に影響を与える rlimit はありません。

ulimit の一部の実装によって報告される PIPEBUF bash のように および ksh のいくつかの実装 rlimit ではありませんが、パイプへの書き込みがアトミックであることが保証される最大サイズであるため、ここでは関係ありません。パイプ自体のサイズ (@dsmsk80 によって報告された Linux では 64kB) 自体は、実際には制限ではありません。それは cmd2 と同じくらいだと言っているだけです cmd1 の後でもパイプに書き込むことができます からの読み取りを停止しました。

ただし、その cmd1 には制限があります しか読めない そのファイルから。これはパイプであるため、そのファイルに書き込むことも、ファイル内を前後にシークすることもできません。

zsh 通常の一時ファイルを使用したコマンド置換の 3 番目の形式があります:

cmd1 =(cmd2)

cmd1 を呼び出します cmd2 の出力を含む一時ファイル .その場合 cmd1 後に実行されます 同時にではなくcmd2。ファイルのサイズの制限に達している可能性があります。

<<<(...) を実装しているシェルを知りません オペレーター。ただし、<<< があります zsh の演算子 (rc の Unix ポートの同じオペレーターから着想を得ています。 ) ksh93 の最近のバージョンにも見られる と bash . << のバリエーションです ヒアストリングと呼ばれるヒアドキュメント演算子。

中:

cmd <<< something

これは標準と同じです:

cmd << EOF
something
EOF

シェルは something\n で一時ファイルを作成します 新しいプロセスへの標準入力としてのコンテンツとフィードとして、そのファイルのリンクを解除し、cmd を実行します その新しいプロセスで。繰り返しますが、これは通常のファイルであるため、ファイルの最大サイズの rlimit に達する可能性があります。

これで <<< を組み合わせることができます $(...) の演算子 (コマンド置換) 何らかの方法で zsh をエミュレートする の =(...) bash の演算子 と ksh93 :

cmd1 <<<"$(cmd2)"

cmd2 を実行します stdout がパイプにリダイレクトされます。パイプの反対側で、シェルは cmd2 の出力を読み取ります 末尾の改行文字を除いて保存し、改行文字を 1 つ追加して一時ファイルに保存し、cmd1 を呼び出します。 その一時ファイルを stdin として読み取るために開いた状態で (cmd2 の場合は機能しないという別の制限があることに注意してください) 出力には NUL 文字が含まれます)。

=(...)のように 、あなたはそれを書く必要があります:

cmd1 /dev/fd/3 3<<<"$(cmd3)"

シェルは一時ファイルに書き込む前に、メモリ内の cmd3 の出力全体を読み取る必要があることに注意してください。そのため、最大ファイル サイズに加えて、メモリ使用量の制限に達する可能性もあります。

また、バージョン 5 以降、bash にも注意してください。 cmd1 を呼び出す前に、一時ファイルへの書き込み権限を取り除きます 、だから cmd1 が必要な場合 そのファイルを変更できるようにするには、次の方法で回避する必要があります:

{
  chmod u+w /dev/fd/3 && # only needed in bash 5+
  cmd1 /dev/fd/3
} 3<<<"$(cmd3)"

<(cmd) 形式の Bash プロセス置換 と >(cmd) システムがサポートしている場合、名前付きパイプで実装されます。コマンド cmd 入力/出力がパイプに接続された状態で実行されます。あなたが実行するとき。 cat <(sleep 10; ls) 作成されたパイプは、ディレクトリ /proc/pid_of_cat/fd の下にあります。 .この名前付きパイプは、現在のコマンドに引数として渡されます (cat ).

パイプのバッファ容量は、dd というトリッキーな使い方で見積もることができます sleep の標準入力にゼロデータを送るコマンド コマンド (何もしません)。どうやら、プロセスはしばらくスリープ状態になるため、バッファがいっぱいになります:

(dd if=/dev/zero bs=1 | sleep 999) &

少し待ってから USR1 を送信してください dd への合図 プロセス:

pkill -USR1 dd

これにより、I/O 統計を出力するプロセスが作成されます:

65537+0 records in
65536+0 records out
65536 bytes (66 kB) copied, 8.62622 s, 7.6 kB/s

私のテストケースでは、バッファサイズは 64kB です (65536B ).

<<<(cmd) の使い方 拡張?標準入力で展開されてコマンドに渡されるヒアドキュメントのバリエーションであることは承知しています。

うまくいけば、サイズに関する質問に光を当てることができます。速度に関してはよくわかりませんが、どちらの方法でも同様のスループットを実現できると思います。


Linux
  1. .htaccessファイルでリダイレクトを作成するための初心者向けガイド

  2. Web証明書のCSRファイルを作成します。

  3. プロセス置換とパイプ?

  1. 一部のコマンドでBashプロセス置換が機能しないのはなぜですか?

  2. xauth が .Xauthority ファイルを作成しない

  3. Linux プロセスのメモリをファイルにダンプする

  1. tcpdumpのフィルタリング:カオスからの順序の作成

  2. ファイルを作成しているプロセスを特定する方法は??

  3. 変数の拡張を延期する方法は?