
いろいろな記事や質問を読んでいますが、毎日使用している内容がまだ混乱していて、それがどれほど混乱しているのか、全く気付いていませんでした。私はLinuxで(名前付き)パイプを試しています。
初めて 試みは簡単です。パイプバッファがどのように機能するかをご覧ください。
#1
mkfifo /tmp/mypipe
#2
echo "Hello World" >/tmp/mypipe
ctrl+c
#3
cat /tmp/mypipe
観察するecho
:データを読み取る前に終了すると、cat
パイプには何も書き込まれません(cat
実行され続けますが、パイプから何も読み込まれません)。を入力しproducent >named_pipe
て終了すると、producent
パイプバッファのサイズに一致するデータの一部が書き込まれ、named_pipe
読み込まれるまでここに残っていると仮定しますconsument
(これはうまくいきません)。だから私が次にしたことは次のとおりです。
2位consument
パイプのもう一方の端に接続してみてください。
#1
mkfifo /tmp/mypipe
#2
echo "Hello World" >/tmp/mypipe
#3
cat /tmp/mypipe
観察する:コマンドはメッセージをcat
表示し、両方のプロセスが終了します。"Hello World"
ここで興味深いのは、手順2ではps -elf
コマンドが表示されないことですecho
。echo
誰かがパイプからデータを読み取るのを待っているようです。これが最初の試みでパイプに何も印刷されない理由です。
3番目の場所 パイプコマンドが「永久に」実行され、パイプに書き続け、何が起こるかを見てください。
#1
mkfifo /tmp/mypipe
#2
yes >/tmp/mypipe
#3
cat /tmp/mypipe
観察する:これは期待どおりに機能し、パイプに渡された内容をcat
印刷します。しかし、代替をyes
試してみました。これにより、コマンドが終了するまで何も印刷されません。cat
tail -f
tail
yes
4位 努力するのが最大の謎です。
# 1#
mkfifo /tmp/mypipe
# 2#
for i in $(seq 1 10000); do echo -n $i"|"> /tmp/mypipe; done
# 3#
for i in $(seq 1 10); do echo "${i}# Read:"; cat /tmp/mypipe && echo ""; done
その後、3#コマンドは同様の内容を入力し始めます。
1# Read:
1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56|57|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|73|74|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99|100|101|102|103|104|105|106|107|108|
2# Read:
109|
3# Read:
110|
4# Read:
111|
5# Read:
112|
6# Read:
113|114|115|
7# Read:
116|
8# Read:
117|
9# Read:
118|119|120|121|122|123|124|125|126|127|128|129|130|131|132|133|134|135|136|137|138|139|140|141|142|143|144|145|146|147|148|149|150|151|152|153|154|155|156|157|158|159|160|161|162|163|164|165|166|167|168|169|170|171|172|173|174|175|176|177|178|179|180|181|182|183|184|185|186|187|188|189|190|191|192|193|194|195|196|197|198|199|200|201|202|203|204|205|206|207|208|209|210|211|212|213|214|215|216|217|218|219|220|221|222|223|224|225|226|227|228|229|230|231|232|233|234|235|236|237|238|239|240|241|242|243|244|245|246|247|248|249|250|251|252|253|254|255|256|257|258|259|260|261|262|263|264|265|266|267|268|269|270|271|272|273|274|275|276|277|278|279|280|281|282|283|284|285|286|287|288|289|290|291|292|293|294|295|
10# Read:
296|297|298|299|300|301|302|303|304|305|306|307|308|309|310|311|312|313|314|315|316|317|318|319|320|321|322|323|324|325|326|327|328|329|
質問:
最初と2番目の試み:
- この特別な場合、名前付きパイプは
|
bashで知られている古典的なパイプと同じですか? - 生産者は常に消費者を待っていますか?それでは、パイプバッファの目的は何ですか?このような行為を通信遮断といいますか?
Linuxは、消費者がパイプに接続して通信できる時期をどのように知ることができますか?試してみましたが、
lsof named_pipe
情報は提供されません。この情報はどこに保存されていますか?また、次のことを試しましたが、結果はcat
パイプから読み取れないことです。#1 mkfifo /tmp/mypipe #2 echo 1 >/tmp/mypipe #3 rm /tmp/mypipe #4 mkfifo /tmp/mypipe #5 cat /tmp/mypipe
入力中:
producent >/tmp/mypipe
入力と同じcommand |
誰かがあるコマンドを別のコマンドにパイプしたいのですが、パイプの後に別のコマンドを入力するのを忘れてしまったことを意味します(ps
この場合は最初に表示せずcommand
)。
3回目の試み:
cat
違いは何ですか?tail -f
4回目の試み:
ここで何が起こっているのでしょうか?データブロックサイズの読み取りが不正確な理由は何ですか?私は出力が次のようになると期待しています:
1# 読み: 1| 2# 読み取り: 2|3# 読み取り: 3|
PS:他の起動コマンドシーケンス(最初に読み込んだ後に書き込む)も試しましたが、結果は同じです。
PPS:これは明確であることを願っていますが、生産者=パイプに書くプロセスです。コンシューマ = パイプからデータを読み取るプロセスです。
主にCスクリプトの知識が少ない人にこの内容を説明できますか?とても感謝しています。
編集者の回答:Joe Sewell
- 削除確認 2.
私が知っている限り、両方とも並列に実行されます。つまり、次の2つは同じではありません。
find | less
そして
find > /tmp/file && less /tmp/file
次のコマンドを実行すると、HDDが機能せず、less
コマンドに表示されるデータが十分になるまで停止するように見えることがさらに観察されました。
find | less
shifg+g
(ファイルの末尾に移動)をクリックすると、less
ハードドライブはすぐに動作を開始し、データの出力を開始します。これはless
、コマンドに表示するのに十分なデータがあるときにfind
データを生成しないように指示することを意味しますか?これを同期といいますか?パイプに書き込まれたデータの転送量はバッファサイズと一致しますか?また、クリックしてfind
ステータス(ps aux
-stat列)が変更されたことを確認しました。S+ to D+
shift+g
less
S interruptible sleep (waiting for an event to complete)
D uninterruptible sleep (usually IO)
+ is in the foreground process group.
┌─[wakatana@~] [63 files, 178Mb]
└──> ps aux | egrep -w 'less|find'
wakatana 6071 0.0 0.0 12736 1088 pts/5 S+ 23:15 0:00 find
wakatana 6072 0.0 0.0 7940 928 pts/5 S+ 23:15 0:00 less
wakatana 6183 0.0 0.0 7832 892 pts/6 S+ 23:20 0:00 egrep --color=auto -w less|find
┌─[wakatana@~] [63 files, 178Mb]
└──> ps aux | egrep -w 'less|find'
wakatana 6071 0.0 0.0 12808 1304 pts/5 D+ 23:15 0:00 find
wakatana 6072 0.0 0.0 9556 2508 pts/5 S+ 23:15 0:00 less
wakatana 6193 0.0 0.0 7832 892 pts/6 S+ 23:21 0:00 egrep --color=auto -w less|find
誰がこの信号を生産者に送りますか?それでは、消費者は自分がすでに製品があるパイプライン(私のrmパイプラインの例のように)に接続されていることをどうやって知ることができますか?
削除確認
削除確認
私は新しい行が私を混乱させるとは思わない。以前に観察した内容(そしてあなたの確認:「はい、両端はお互いを待ちます」)に基づいています。私はこれを期待しています:
I. 最初のループの最初の繰り返しはパイプに書き込まれ、誰も読みませんので、ここで待ちます。
2. 2 番目のループが実行されると、最初の反復で最初のループによって書き込まれたデータが読み込まれ、ここには何も書き込まれなくなり、読み取れなくなります。
三。 2番目のループは、最初のループが次のデータを書き込むのを待つか(順序は重要ではないため)、最初のループは2番目のループが書き込んだデータを読み取るのを待ちます。
したがって、1 回の書き込みが 1 回の読み取りに対応すると予想されます。また、ループが実行されていないことを確認していたので、コンシューマがコンテンツを読み取らなくても何も印刷されない場合でも、STDOUTに何かを印刷するかどうかを確認するために元のコマンドのいくつかを修正しました。
for i in $(seq 1 10000); do
if [ $(( $i % 5 )) -eq 0 ]; then
echo $i;
else
echo -n $i"|"> /tmp/mypipe;
fi;
done
「作成プロセスでは改行文字がまったく送信されないので、読者は「十分」という言葉を聞くまで読んでください。」
- 誰が消費者に十分だと言うのでしょうか?
「最初のケースでは、fifoのバッファがいっぱいになる可能性があります」
- 上記のように通信がブロックされている場合は、バッファをどのように入力しますか?
「それで読者に駆けつけました」
- どういう意味ですか?申し訳ありません。私の英語力が悪いです。
「通信を非同期化する方法があるが…」
- この場合、非同期と同期の違いが何であるかを簡単に説明できますか?
答え1
質問リストに番号で回答するには、次の手順に従ってください。
fifoとも呼ばれる名前付きパイプは、デフォルトでシェルによって生成された名前付きパイプと同じです。主な違いは、2つの端の間のシェルバージョンの同期が直感的ですが、使用されているように見える名前付きパイプには、シェルが実行する操作についての知識が必要であることです。
はい、両側はお互いを待っています。 fifoの目的は、あるプロセスの出力を別のプロセスの入力に渡すシェルパイプの目的と同じです。彼らいいえ一時ファイル。私はこれがあなたが混乱している場所だと思います。このようなシェルコマンドの場合
cat somefile.txt | less
、両方コマンドはフォークされたプロセスとして同時に実行され、パイプは両方のプロセスを同期させるために使用されます。私の記憶が正しければCで修正すればいいのですが、シェルコマンドを使うとそれほど簡単ではありません。プロセスはパイプのもう一方の端が接続されたときに信号を受け取ることができますが、上記のように、全体的な意図は通常、2つのプロセスを同期状態に保つことです。作成者は何かを送信し、書き込み操作が完了したことを知って続行できます。
bash
そしてtcsh
それはあなたが「忘れる」ことを許可しません。コマンドは実行されません。tail -f
stdin
何でも表示するには、EOFを取得するまで(この場合)ストリーム全体を読み取る必要があります。あなたの実験ではエンディングは発生しませんでした。cat
一方、入力処理はすぐに開始できます。書き込みプロセスでは改行文字がまったく送信されないため、読者は「十分」という言葉を聞くまで読むだけです。最初のケースでは、fifoのバッファがいっぱいになり、リーダにフラッシュされることがあります。後続の出力は似ている可能性があり、システムタイミングによって異なります。
ここで別の混乱した問題に対処します。シェルはリダイレクトを処理します。今後コマンドを実行します。これは、FIFOのもう一方の端が接続されるのを待っているcat
ため、プロセスリストに表示されないことを意味します。bash
今後ランニングcat
または作家に関連するすべて。同様に、ライターが接続されるまで読み取りコマンドは実行されません。
私の考えでは、あなたの最大の誤解は名前付きパイプですいいえ一時ファイル。名前のない通路でもありません。通信を非同期にする方法がありますが、次から実際の一時ファイルを作成する方が/tmp
良いと思います。する両方のプロセスを同時に実行したいです。
答え2
find | less
shift+g
(ファイルの末尾に移動)をクリックすると、less
ハードドライブはすぐに動作を開始し、データの出力を開始します。これはless
、コマンドに表示するのに十分なデータがあるときにfind
データを生成しないように指示することを意味しますか?
カント。パイプはread()
sとsに使用できますwrite()
。less
言うfind
何もない- ただし、read()
パイプを所有するシステムカーネルは、関連プロセスがある限りパイプをフラッシュしません。これは、パイプバッファがいっぱいになり、カーネルが他のバッファを許可しないため、続行find
write()
できなくなるまで続きます。これもこうだwrite()
write()
find
詰まった編集する。パイプ入力端にジャンプすると、less
read()
パイプ内でわずかな倍数が発生します。(すべて)find
- これでパイプバッファをwrite()
再利用できるようになりました。ディスク検索を再開し、バッファを再充填するか、操作を完了しようとします。
同じ理由名前付きパイプ- これはまったく同じです - カーネルがパイプの両端を疑似ファイルに関連付けることに同意することを除いて協会- ファイルシステムのどこかにあります。時:
mkfifo pipe
echo > pipe &
rm pipe
mkfifo pipe
cat pipe
...あなたは一緒に働いています2つの異なる管路。最初のものunlink()
は、edで指定されたファイルシステムに関連付けられていますが、rm
まだecho
パイプで待っていますread()
。しかし、今プロセスが他端を見つける可能性はほとんどありません。実際には、基本的に名前付きパイプを使用しながらこの方法で匿名にすることができます。これはセキュリティ上の理由から一般的に最良の方法です。
努力する:
mkfifo pipe
exec 3<>pipe 4<>pipe
cat <&3 >out.log &
rm pipe
echo read this, cat\! >&4