Nを使用すると、sed出力に混乱します。これらの結果について誰かが説明できますか?


8

私はセッドを学んでいます。N(次は複数行)に出会うまで、すべてが順調に進んでいるように見えました。このファイル(guide.txt)は、練習/理解/コンテキストの目的で作成しました。上記のファイルの内容は次のとおりです...

This guide is meant to walk you through a day as a Network
Administrator. By the end, hopefully you will be better
equipped to perform your duties as a Network Administrator
and maybe even enjoy being a Network Administrator that much more.
Network Administrator
Network Administrator
I'm a Network Administrator

したがって、私の目標は、「ネットワーク管理者」のすべてのインスタンスを「システムユーザー」に置き換えることです。「ネットワーク管理者」の最初のインスタンスは改行(\ n)で区切られているため、「管理者」で始まる行と「ネットワーク\ n」で終わる前の行を追加するには、複数行の次の演算子(N)が必要です。 。問題ない。しかし、他のすべての「ネットワーク管理者」単一行インスタンスもキャッチしたいと思います。

私の調査から、2つの置換コマンドが必要になることがわかりました。1つは改行で区切られた文字列用で、もう1つは他の文字列用です。また、置換一致を含む最後の行と次の複数行のために、いくつかのジャイブが発生しています。だから私はこれを作ります...

$ sed '
> s/Network Administrator/System User/
> N
> s/Network\nAdministrator/System\nUser/
> ' guide.txt

これはこれらの結果を返します...

This guide is meant to walk you through a day as a System
User. By the end, hopefully you will be better
equipped to perform your duties as a System User
and maybe even enjoy being a Network Administrator that much more.
System User
Network Administrator
I'm a System User

単一行の置換は「ネットワーク管理者」のすべての「通常の」インスタンスをキャッチし、それを「システムユーザー」にスワップアウトすると思いましたが、複数行のステートメントは改行で区切られたインスタンスでその魔法を働かせますが、それが返されたこと、私が考えるところ、予期しない結果を見ることができます。

少しいじった後、私はこれに着陸しました...

$ sed '
> s/Network Administrator/System User/
> N
> s/Network\nAdministrator/System\nUser/
> s/Network Administrator/System User/
> ' guide.txt

ちなみに、私は望ましい出力を得ます...

This guide is meant to walk you through a day as a System
User. By the end, hopefully you will be better
equipped to perform your duties as a System User
and maybe even enjoy being a System User that much more.
System User
System User
I'm a System User

なぜこれが機能し、元のsedスクリプトが機能しないのですか?本当に理解したいです。

助けてくれてありがとう。


セドを学ぶためにあなたに良い!Sed使用して、このサイトで非常によく似た質問を解決しました。興味があるかもしれません。
ワイルドカード

そして、他の2つのトリッキーなSedの例:unix.stackexchange.com/a/277375/135943、unix.stackexchange.com / a / 257913/135943
Wildcard

回答:


6

学習している間sed、@ John1024の答えに時間をかけて説明します。

1)\n置換文字列で使用していることに注意してください。これはGNU sedで機能しますが、POSIXの一部ではないため、nsedの多くのにバックスラッシュとを挿入します(\nパターンでの使用は移植可能です)。

これの代わりに、私は行うことをお勧めしますs/Network\([[:space:]]\)Administrator/System\1Us‌​er/g[[:space:]]は改行または空白に一致するためs、2つのコマンドは必要ありませんが、1つに結合します。で囲むことにより\(...\)、置換で参照できます。\1は、の最初のペアで一致したものに置き換えられ\(\)ます。

2)2行のパターンを正しく一致させるには、N;P;Dパターンを知っておく必要があります。

 sed '$!N;s/Network\([[:space:]]\)Administrator/System\1User/g;P;D'

N常にそれがして、「対処」だ理由です最後の行を除いて、次の行(追加された$!(=そうでない場合は、最後の行、あなたは常にpreceedに検討すべきであるN$!。誤ってスクリプトを終了避けるために)そして、交換後Pにのみ印刷しますパターンスペースの最初の行とはDこの行を削除し、パターンスペースの残りの部分から次のサイクルを開始します(次の行を読み取らずに)これは、おそらく最初に意図したものです。

このパターンを覚えておいてください、あなたはしばしばそれを必要とするでしょう。

3)複数行の編集に役立つもう1つのパターン、特に3行以上の場合:ジョンに提案したように、スペース収集を保持します。

sed 'H;1h;$!d;g;s/Network\([[:space:]]\)Administrator/System\1Us‌​er/g'

説明のために繰り返しHます。ホールドスペースに各行を追加します。これにより最初の行の前に余分な改行が発生するため、最初の行を追加する代わりに最初の行を移動する必要があります1h。以下$!dは、「最後の行を除くすべての行について、パターンスペースを削除してやり直す」ことを意味します。したがって、スクリプトの残りの部分は最後の行に対してのみ実行されます。この時点で、ファイル全体がホールドスペースに収集されます(非常に大きなファイルには使用しないでください)。gそれをパターンスペースに移動するので、-zオプションのように、すべての置換を一度に行うことができます。 GNU sed

これは、覚えておかなければならないもう1つの便利なパターンです。


うわー!素晴らしい説明!これとジョンの回答を組み合わせると、この問題に対する洞察が深まり、一般的にSEDになりました。もっと学ぶべきことがあるようです。私はあなたの両方の解決策を答えとして確認できたらいいのにと思います。両方の取り組みに感謝します。彼らは大歓迎です。
dlowrie290 2017年

7

まず、ソリューションが実際に機能しないことに注意してください。次のテストファイルを検討してください。

$ cat test1
Network
Administrator Network
Administrator

次に、コマンドを実行します。

$ sed '
 s/Network Administrator/System User/
 N
 s/Network\nAdministrator/System\nUser/
 s/Network Administrator/System User/
 ' test1
System
User Network
Administrator

問題は、コードが最後のコードで代用されないことNetwork\nAdministratorです。

このソリューションは機能します:

$ sed ':a; /Network$/{$!{N;ba}}; s/Network\nAdministrator/System\nUser/g; s/Network Administrator/System User/g' test1
System
User System
User

これをあなたにも適用できますguide.txt

$ sed ':a; /Network$/{$!{N;ba}}; s/Network\nAdministrator/System\nUser/g; s/Network Administrator/System User/g' guide.txt 
This guide is meant to walk you through a day as a System
User. By the end, hopefully you will be better
equipped to perform your duties as a System User
and maybe even enjoy being a System User that much more.
System User
System User
I'm a System User

重要なのは、で終わらない行が見つかるまで行を読み続けることですNetwork。それが完了すると、置換を行うことができます。

互換性に関する注意:上記のすべて\nが置換テキストで使用されます。これにはGNU sedが必要です。BSD / OSX sedでは動作しません。

[ フィリポスへのヒント。]

複数行バージョン

明確にするのに役立つ場合は、同じコマンドを複数行に分割しています。

$ sed ':a
    /Network$/{
       $!{
           N
           ba
       }
    }
    s/Network\nAdministrator/System\nUser/g
    s/Network Administrator/System User/g
    ' filename

使い方

  1. :a

    これにより、ラベルが作成されますa

  2. /Network$/{ $!{N;ba} }

    この行がで終わるNetwork場合、これが最後の行でない場合($!)、次の行を読み取って追加し(N)、ラベルaba)に戻ります。

  3. s/Network\nAdministrator/System\nUser/g

    中間の改行で置き換えます。

  4. s/Network Administrator/System User/g

    中間ブランクで代用します。

よりシンプルなソリューション(GNUのみ)

(SED GNUでない BSD / OSX)、我々は唯一の代替コマンドが必要になります。

$ sed -zE 's/Network([[:space:]]+)Administrator/System\1User/g' test1
System
User System
User

そしてguide.txtファイル上:

$ sed -zE 's/Network([[:space:]]+)Administrator/System\1User/g' guide.txt 
This guide is meant to walk you through a day as a System
User. By the end, hopefully you will be better
equipped to perform your duties as a System User
and maybe even enjoy being a System User that much more.
System User
System User
I'm a System User

この場合、-z最初のNUL文字まで読み取るようにsedに指示します。テキストファイルにはnull文字が含まれないため、ファイル全体を一度に読み取る効果があります。その後、行の欠落を心配することなく置換を行うことができます。

この方法は、ファイルが巨大な場合(通常はギガバイトを意味します)には適していません。そのサイズが大きい場合、一度にすべてを読み取ると、システムRAMに負担がかかる可能性があります。

GNUとBSDの両方で動作するソリューションsed

Philliposが提案したように、以下はポータブルソリューションです。

sed 'H;1h;$!d;x;s/Network\([[:space:]]\)Administrator/System\1Us‌​er/g'

1
すばらしい情報、ジョン!これにいくつかの光を当ててくれてありがとう、そしてあなたの代わりの解決策はとても素晴らしいです。そうは言っても、なぜ私のソリューションがソリューションではないのかはまだわかりません。動作するように見えますが、test.txtファイルでは動作しません。なぜ私のソリューションは機能しているように見えますが、実際には機能していませんか?助けてくれてどうもありがとう。
dlowrie290 2017年

1
@ dlowrie290ソリューションはペアで行を読み取ります。Network Administratorがそのペアの1行目と2行目で分割されている場合、ソリューションは正常に置換を行います。次に、これらの2行を印刷して、次のペアを読み取ります。ただし、最初のペアの2行目がで終わりNetwork、2番目のペアの最初の行がで始まるAdministrator場合、コードはそれを逃します。私のコードは、で終わらないものを見つけるまで行を読み込むことでこれを回避していNetworkます。
John1024 2017年

2
あなたの最初の複数行のソリューションをもGNU拡張に依存することに注意してくださいsed\n交換では、標準で定義されていませんが。sed 'H;1h;$!d;x;s/Network\([[:space:]]\)Administrator/System\1User/g'それを行うためのポータブルな方法です。
フィリポス

@Philippos優れた点。ポータブルソリューションを含むように回答が更新されました。
John1024

1
説明してくれてありがとう、ジョン!繰り返しますが、素晴らしいものとあなたの時間/努力は大いに感謝されます!
dlowrie290 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.