web-dev-qa-db-ja.com

:a; $!N;の意味は何ですか? sedコマンドで?

$ (echo hello; echo there) | sed ':a;$!N;s/\n/string/;ta'
hellostringthere

上記のsedコマンドは、改行文字をストリング「string」に置き換えます。しかし、単一引用符内の:a;$!N;s/\n/string/;taの意味がわかりません。中間部分s/\n/string/を知っています。しかし、最初(:a;$!N;)と最後(ta)の部分の機能はわかりません。

10
Avinash Raj

これらは、明らかに不可解なsedコマンドです。具体的には(man sedから):

:ラベル
bおよびtコマンドのラベル。

tラベル
。ラベルが省略されている場合は、スクリプトの最後に分岐します。

n N入力の次の行をパターンスペースに読み込み/追加します。

したがって、投稿したスクリプトは、次のように分類できます(読みやすいようにスペースを追加します)。

sed ':a;  $!N;  s/\n/string/;  ta'
     ---  ----  -------------  --
      |     |        |          |--> go back (`t`) to `a`
      |     |        |-------------> substitute newlines with `string`
      |     |----------------------> If this is not the last line (`$!`), append the 
      |                              next line to the pattern space.
      |----------------------------> Create the label `a`.

基本的に、これがしていることは、擬似コードで次のように書くことができます。

while (not end of line){
    append current line to this one and replace \n with 'string'
}

より複雑な入力例を使用すると、これをもう少しよく理解できます。

$ printf "line1\nline2\nline3\nline4\nline5\n" | sed ':a;$!N;s/\n/string/;ta'
line1stringline2stringline3stringline4stringline5

!$が必要な理由はよくわかりません。私が知る限り、同じ出力を得ることができます

printf "line1\nline2\nline3\nline4\nline5\n" | sed ':a;N;s/\n/string/;ta'
16
terdon

whyについて多くの混乱が見られるので、Nを実行するときに最後の行が除外されます(行アドレス文字列$!を通じて)、OPの意味について混乱しているため、この回答を投稿します:a;$!N;in a sed command、彼が投稿した特定のtheだけでなく。

さて、Nの代わりに$!Nを使用する利点は、Nの後の最後の行で "重要"(読み続ける)コマンドが実行されないため、提案された例(OPおよび@terdon)では明白ではありませんコマンド。 (実際、その行アドレスを削除しても結果は同じです。)

より複雑な例(たとえば、ファイル内のthis sentenceを置換し、2つの単語を1行と2行に表示することもあります)、Nコマンドの最後の行を除外することが重要です!最後の行が除外されていない場合、その上でNを実行すると、sedEOFにヒットしてすぐに終了し、後続のすべてのコマンド(分岐コマンド、つまりtおよびb)が実行されなくなります。

単純すぎる例では、$!を安全に削除し、sedNの実行に失敗させ、一致する\nがないため、中止されたsコマンドが実行されても何もしません。