次の内容で「test」というテストファイルを作成しました。
xxx
yyy
zzz
私は次のコマンドを実行しました。
(sed '/y/ q'; echo aaa; cat) < test
わかりました:
xxx
yyy
aaa
zzz
それから私は以下を実行しました。
cat test | (sed '/y/ q'; echo aaa; cat)
そして得る:
xxx
yyy
aaa
質問
sed
「y」行が表示されるまで読み、印刷してから停止します。最初のケースでは、catは残りの内容を読み取って印刷しますが、2番目のケースではそうではありません。
これらの行動の違いの後に隠れている現象が何であるかを説明できる人はいますか?
また、Ubuntu 16.04とCentos 6ではこのように動作しますが、Centos 7では両方のコマンドが「zzz」を印刷しないことがわかりました。
答え1
入力ファイルが次のような場合閲覧可能(通常のファイルから読み込むような)または検索できません(パイプで読むのと似ています)sed
(および他の標準ユーティリティ)は異なる動作をしますINPUT FILES
。このリンク)。
引用文書:
標準ユーティリティが検索可能な入力ファイルを読み取り、ファイルの終わりに到達する前にエラーなしで終了する場合、ユーティリティは、開かれたファイル記述のファイルオフセットがユーティリティが処理した最後のバイトの後に正しく配置されていることを確認する必要があります。
だから:
(sed '/y/ q'; echo aaa; cat) < test
sed
uitコマンドはEOFに達する前に実行されるq
ため、行の先頭にファイルオフセットを残して残りの行を印刷することができます(GNU sedは場合によってはPOSIXと互換性がありません。以下を参照)zzz
。cat
そして、文書を続けると次のようになります。
検索できないファイルの場合、ファイルのオープンファイル記述にファイルオフセット状態は指定されません。
この場合、動作は指定されません。ほとんどの標準ツール(付属)はsed
できるだけ多くの入力を消費します。yyy
行を読み取って渡し、q
ファイルオフセットを復元しないので、何も残りませんcat
。
GNUはsed
標準に準拠しておらず、システムのstdio実装とglibcのバージョンによって異なります。
$ (gsed '/y/ q'; echo aaa; cat) < test
xxx
yyy
aaa
ここの結果は、CEPHバックエンドを備えたOpenstack上で動作するMac OSX 10.11.6、仮想マシンCentos 7.2 - glibc 2.17、Ubuntu 14.04 - glibc 2.19から得られました。
これらのシステムでは、-u
オプションを使用して標準動作を達成できます。
(gsed -u '/y/ q'; echo aaa; cat) </tmp/test
パイプの場合:
$ cat test | (gsed -u '/y/ q'; echo aaa; cat)
xxx
yyy
aaa
zzz
sed
一度に1バイトずつ読み取る必要があるため、パフォーマンスは非常に非効率的です。部分出力strace
:
$ strace -fe read sh -c '{ sed -u "/y/q"; echo aaa; cat; } <test'
...
[pid 5248] read(3, "", 4096) = 0
[pid 5248] read(0, "x", 1) = 1
[pid 5248] read(0, "x", 1) = 1
[pid 5248] read(0, "x", 1) = 1
[pid 5248] read(0, "\n", 1) = 1
xxx
[pid 5248] read(0, "y", 1) = 1
[pid 5248] read(0, "y", 1) = 1
[pid 5248] read(0, "y", 1) = 1
[pid 5248] read(0, "\n", 1) = 1
yyy
...