GNU `sed`が時々分岐コマンドなしでループを生成するのはなぜですか?

GNU `sed`が時々分岐コマンドなしでループを生成するのはなぜですか?

次の素晴らしい実験sedコードを見てください。

seq 3 | timeout 5s sed 'H;${g;D}'

...timeout 5sこれがなければ、コンピュータは停止しますが(5秒後に停止せず)、まず次のような結果が出力されます。

1
2

または、p保持バッファを無限に印刷するには、次を追加します。

seq 3 | timeout 5s sed 'H;${g;p;D}'

奇妙なことに、Dコマンドだけが無限ループを引き起こすようです(つまりdp、または)に置き換えようとしましたが、Pよく文書化されていません。これ牛に似た一種の栄養 sed info文書には次のように記載されています。

'D'
     If pattern space contains no newline, start a normal new cycle as
     if the 'd' command was issued.  Otherwise, delete text in the
     pattern space up to the first newline, and restart cycle with the
     resultant pattern space, without reading a new line of input.

ただし、これはユーザーに無限ループの可能性を警告しません。おそらくg;D内部行カウンターがリセットされ、sedすぐ後ろにジャンプします$

分岐ドアのないこの種のループはどこにも文書化されていますか?そうでなければ、誰かがそれがどのように機能するかを説明できますか?

ベストアンサー1

はい、これは奇妙な問題ですが、明らかに予想される問題です。

重要な理由を段階的に見てみましょう。

テストでは、seq 5 | sed 'H;${g;d}'1行に1つずつ1から4まで印刷しますが、最後の数字は印刷しません。5なぜですか?

スピード:

  • seq 51行に1つずつ、1から5までのすべての数値を生成します。
  • sed最初の行が受信されると、1予約済みスペースに保存されます(デフォルトでは改行文字を追加した後H)。
  • 実行する項目がないため(次のコマンドは最後の行でのみ実行されます$)、その行も印刷されます(保持スペースを除く)。
  • 各行に追加された改行文字の後の予約済みスペースに追加され、印刷されます。
  • 最後の行でコマンドがg;d実行されます。 1つ目は、このとき予約された空間全体を呼び出して\n1\n2\n3\n4\n5すぐに使用して停止するd方法だ。

予約済みスペースの状態を実際に表示するには、次のsedスクリプトを実行できます。

$ seq 5 | sed 'H;x;l;x;${g;d}'
\n1$
1
\n1\n2$
2
\n1\n2\n3$
3
\n1\n2\n3\n4$
4
\n1\n2\n3\n4\n5$

D同じように動作すると仮定d巨大な違い:ただパターン空間に新しい行がない場合。 ~からinfo sed

'D'
パターンスペースに改行文字が含まれている場合は、最初の改行文字までパターンスペースのテキストを削除し、新しい入力行を読み取らずに結果のパターンスペースにループを再開します。

パターンスペースに改行文字が含まれていない場合は、「d」コマンドが実行されたかのように、一般的な新しいループが開始されます。

したがって、d次に置き換えるときにDこのスクリプトを実行してください。

seq 5 | sed 'H;x;l;x;${g;D}'

無制限の出力が得られます。最初の行を削除しますD:数字と改行、はい。ただし、最初に戻って(削除されていない)パターン1\n2\n3\n4\n5スペースの予約済みスペースに追加されます。最初のループでは、aが予約済みスペース1\n2\n3\n4\n5に追加され、2倍になります。各サイクルの正確な値は重要ではありません。重要なことは、サイクルごとに値が大きくなることです。\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5

これで、以前のパターンスペースを消去するとD機能できます。

$ seq 5 | sed 'H;x;l;x;${g;z;D}'
\n1$
1
\n1\n2$
2
\n1\n2\n3$
3
\n1\n2\n3\n4$
4
\n1\n2\n3\n4\n5$

もちろん。

驚くべき副作用を除いて、普通ではなく、すべてが期待どおりに機能しました。

おすすめ記事