序章

sedストリームエディタは、非常に少ない入力で抜本的な変更を加えることができる強力な編集ツールです。 sedに関する前回の記事では、sedを使用してテキストを編集する基本について説明しました。

この記事では、さらに高度なトピックを検討して、紹介を続けます。

:このチュートリアルでは、Ubuntuおよびその他のLinuxオペレーティングシステムにあるsedのGNUバージョンを使用します。 macOSを使用している場合は、さまざまなオプションと引数を持つBSDバージョンがあります。 brew install gnu-sedを使用して、sedのGNUバージョンをHomebrewとともにインストールできます。

このチュートリアルを完了するには、操作するいくつかのファイルが必要です。これは、最初のチュートリアルから持っている必要があります。 それらがない場合は、次のコマンドを使用して再作成できます。

  1. cd
  2. cp /usr/share/common-licenses/BSD .
  3. echo
  4. "this is the song that never ends
  5. yes, it goes on and on, my friend
  6. some people started singing it
  7. not knowing what it was
  8. and they'll continue singing it forever
  9. just because..." > song.txt

さらに、このチュートリアルでは GPL 3ライセンスを使用するため、そのファイルもコピーします。

  1. cp /usr/share/common-licenses/GPL-3 .

お持ちでない場合は、curlでダウンロードできます。

  1. curl -o GPL-3 https://www.gnu.org/licenses/gpl-3.0.txt

ファイルができたので、sedを複数のコマンドで使用して調べます。

複数の編集シーケンスの提供

sedに同時に複数のコマンドを渡したい場合がかなりあります。 これを実現する方法はいくつかあります。

sedは標準の入出力を介して動作するため、パイプラインを介してsedへのさまざまな呼び出しをつなぎ合わせることができます。 このコマンドを実行して、単語andをアパーサンド(&)に置き換え、単語peoplehorsesに置き換えます。

  1. sed 's/and/\&/' song.txt | sed 's/people/horses/'

「&」は「完全に一致したパターン」を意味するため、エスケープする必要があることに注意してください。sed ):

次の出力が表示されます。

Output
this is the song that never ends yes, it goes on & on, my friend some horses started singing it not knowing what it was & they'll continue singing it forever just because...

これは機能しますが、sedを複数回呼び出すと不要なオーバーヘッドが発生し、より多くの入力が必要になり、sedの組み込み機能を利用できません。

各コマンドの前に-eオプションを使用すると、さまざまなコマンドをsedに文字列化できます。 これは、前のコマンドを書き直す方法です。

  1. sed -e 's/and/\&/' -e 's/people/horses/' song.txt

コマンドをつなぎ合わせる別の方法は、セミコロン文字(;)を使用して個別のコマンドを区切ることです。 これは前の例と同じように機能しますが、「-e」は必須ではありません。

  1. sed 's/and/\&/;s/people/horses/' song.txt

-e構成を使用する場合、コマンドごとに個別の単一引用符グループが必要であることに注意してください。 ただし、コマンドをセミコロンで区切る場合、すべてのコマンドは1つの引用符で囲まれたコマンド文字列内に配置されます。 複数のコマンドを表現するこれらの2つの方法は便利ですが、以前の配管技術が依然として必要な場合があります。

=演算子について考えてみます。 この演算子は、既存の各行の間の新しい行に行番号を挿入します。 出力は次のようになります。

  1. sed '=' song.txt

表示される出力は次のとおりです。

Output
1 this is the song that never ends 2 yes, it goes on and on, my friend 3 some people started singing it 4 not knowing what it was 5 and they'll continue singing it forever 6 just because...

ただし、テキストを変更して番号の書式を変更したい場合は、期待どおりに機能しないことがわかります。

実例を示すために、Gコマンドを見てみましょう。このコマンドは、デフォルトで各行の間に空白行を入力します(これは実際にはもっと複雑ですが、後で調べます)。

  1. sed 'G' song.txt

結果は次のとおりです。

Output
this is the song that never ends yes, it goes on and on, my friend some people started singing it not knowing what it was and they'll continue singing it forever just because...

これらの2つのコマンドを組み合わせると、通常の各行と行番号の行の間にスペースが必要になる場合があります。

  1. sed '=;G' song.txt

ただし、何か違うものがあります。

Output
1 this is the song that never ends 2 yes, it goes on and on, my friend 3 some people started singing it 4 not knowing what it was . . . . . .

これは、=演算子が実際の出力ストリームを直接変更するために発生します。 これは、結果をさらに編集するために使用できないことを意味します。

これを回避するには、2つのsed呼び出しを使用し、最初のsed変更を2番目のテキストの単純なストリームとして扱います。

  1. sed '=' song.txt | sed 'G'

これで、期待していた結果が表示されます。

Output
1 this is the song that never ends 2 yes, it goes on and on, my friend 3 some people started singing it . . . . . .

一部のコマンドはこのように動作することに注意してください。特に、複数のコマンドをつなぎ合わせていて、出力が期待したものと異なる場合はそうです。

高度なアドレス指定

sedのアドレス指定可能なコマンドの利点の1つは、正規表現を選択基準として使用できることです。 これは、前に見たように、既知のライン値での操作に制限されないことを意味します。

  1. sed '1,3s/.*/Hello/' song.txt
Output
Hello Hello Hello not knowing what it was and they'll continue singing it forever just because...

代わりに、正規表現を使用して、特定のパターンを含む行のみに一致させることができます。 これを行うには、コマンド文字列を指定する前に、2つのスラッシュ(/)の間に一致パターンを配置します。

  1. sed '/singing/s/it/& loudly/' song.txt
Output
this is the song that never ends yes, it goes on and on, my friend some people started singing it loudly not knowing what it was and they'll continue singing it loudly forever just because...

この例では、文字列singingを含むすべての行で、itが最初に出現した後にloudlyを配置しました。 2行目と4行目はパターンと一致しないため、変更されていないことに注意してください。

アドレス指定の式は、任意に複雑にすることができます。 これにより、コマンドの実行に大きな柔軟性がもたらされます。

これは複雑な例ではありませんが、正規表現を使用して他のコマンドのアドレスを生成する方法を示しています。 次のコマンドは、空白行(行の先頭の直後に行の終わりが続く)と一致し、それらを削除コマンドに渡します。

  1. sed '/^$/d' GPL-3

これが表示される出力です。

Output
GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for . . . . . .

範囲の両側でも正規表現を使用できることに注意してください。 たとえば、STARTという単語のみを含む行から始まり、ENDと表示される行までの行を削除できます。

たとえば、inputfileというファイルを作成します。

  1. echo
  2. "This is an input file
  3. START
  4. this is the text we don't want
  5. END
  6. This is additional text" > inputfile

次に、sedを使用して、STARTENDの間のコンテンツを削除します。

  1. sed '/^START$/,/^END$/d' inputfile

次の出力が表示されます。

This is an input file
This is additional text

ただし、これにより、最初のSTARTから最初のENDまでのすべてが削除され、別のSTARTマーカーが見つかった場合は削除が再開されます。

アドレスを反転したい場合(がパターンと一致しない行で操作する)、感嘆符(!)でパターンをたどることができます。

たとえば、次のコマンドを使用して、空白ではない行を削除できます(それほど有用ではありませんが、単なる例です)。

  1. sed '/^$/!d' GPL-3

sedはデフォルトで行を印刷するため、これにより大きな空白の出力が発生します。

Output

アドレスは、反転するために複雑な式である必要はありません。 反転は、通常の番号付きアドレスでも同じように機能します。

ホールドバッファの使用

sedの複数行対応の編集を実行する機能を向上させる機能の1つは、いわゆる「ホールドバッファー」です。 ホールドバッファは、特定のコマンドで変更できる一時ストレージの領域です。

この余分なバッファが存在するということは、他の行で作業しているときに行を保存し、必要に応じて各バッファを操作できることを意味します。

保持バッファに影響を与えるコマンドは次のとおりです。

  • h :現在のパターンバッファー(現在一致して作業している行)を保持バッファーにコピーします(これにより、保持バッファーの以前の内容が消去されます)。
  • H :現在のパターンバッファを現在の保持パターンの最後に改行(\ n)文字で区切って追加します。
  • g :現在の保持バッファーを現在のパターンバッファーにコピーします。 前のパターンバッファが消去されます。
  • G :現在の保持パターンを現在のパターンバッファーの最後に改行(\ n)文字で区切って追加します。
  • x :現在のパターンと保持バッファーを入れ替えます。

保持バッファの内容は、何らかの方法でパターンバッファに移動されるまで操作できません。

複雑な例を使ってこのアイデアを調べてみましょう。

これは、隣接する線を結合する方法の手順の例です(sedには、実際には、これの多くを処理する組み込みのコマンドがあります。 Nコマンドは、現在の行に次の行を追加します。 練習のために、難しい方法で物事を行うつもりです):

  1. sed -n '1~2h;2~2{H;g;s/\n/ /;p}' song.txt

表示される出力は次のとおりです。

Output
this is the song that never ends yes, it goes on and on, my friend some people started singing it not knowing what it was and they'll continue singing it forever just because...

これは消化することがたくさんあるので、分解してみましょう。

最初に注意することは、-nオプションが自動印刷を抑制するために使用されることです。 sedは、特に指定した場合にのみ印刷されます。

命令の最初の部分は1\~2hです。 最初はアドレス指定であり、最初の行で後続の操作を実行し、その後、1行おきに(各奇数行)実行することを意味します。 hの部分は、一致した行を保持バッファーにコピーするコマンドです。

コマンドの後半はもっと複雑です。 ここでも、アドレス指定から始まります。 今回は、偶数行(最初のコマンドの反対)を参照しています。

コマンドの残りの部分は中括弧で囲まれています。 これは、残りのコマンドが指定されたばかりのアドレスを継承することを意味します。 中括弧がないと、「H」コマンドのみがアドレスを継承し、残りのコマンドはすべての行で実行されます。

Hコマンドは、改行文字に続いて現在のパターンバッファーを、現在の保持パターンの最後にコピーします。

この保持パターン(奇数行、改行文字、偶数行)は、gコマンドを使用してパターンバッファーにコピーされます(前のパターンバッファーを置き換えます)。

次に、改行文字がスペースに置き換えられ、pコマンドで行が印刷されます。

興味がある場合は、Nコマンドを使用するとこれが大幅に短縮されます。 次のコマンドは、今見たのと同じ結果を生成します。

  1. sed -n 'N;s/\n/ /p' song.txt

スクリプトの使用

より複雑なコマンドを使い始めると、テキストエディタでそれらを作成すると役立つ場合があります。 これは、単一のターゲットに適用するコマンドが多数ある場合にも役立ちます。

たとえば、プレーンテキストでメッセージを作成したいが、テキストを使用する前に一連の標準化されたフォーマットを実行する必要がある場合は、sedスクリプトが役立ちます。

sed呼び出しの各セットを入力する代わりに、コマンドをスクリプトに入れて、sedへの引数として指定できます。 sedスクリプトは、生のsedコマンド(通常は一重引用符で囲まれた文字の間の部分)のリストです。

これを試すには、次の内容のsed_scriptという名前の新しいファイルを作成します。

  1. echo
  2. "s/this/that/g
  3. s/people/horses/g
  4. 1,5s/it/that/g" > sed_script

ファイルを保存して、エディターを終了します。

次に、-fスイッチを使用して、ファイルを使用するようにsedに指示します。

  1. sed -f sed_script song.txt

結果は次のようになります。

Output
that is the song that never ends yes, that goes on and on, my friend some horses started singing that not knowing what that was and they'll continue singing that forever just because...

これにより、すべての編集を1つのファイルに入れて、作成した形式に準拠する必要のある任意のテキストファイルで実行できます。

結論

Sedのコマンドは、最初は必ずしも理解しやすいとは限りません。また、その有用性を理解するには、実際の実験が必要になることがよくあります。 このため、実際に必要になる前に、テキストの操作を練習することをお勧めします。 最終目標を念頭に置き、sedのみを使用して実装してみてください。

うまくいけば、この時点で、sedを適切に習得することで得られる力を理解し始めているはずです。 sedに慣れているほど、長期的には必要な作業が少なくなります。