中級版:Linux環境でのテキストストリームの操作
序章
sed
ストリームエディタは、非常に少ない入力で抜本的な変更を加えることができる強力な編集ツールです。 sed
に関する前回の記事では、sedを使用してテキストを編集する基本について説明しました。
この記事では、さらに高度なトピックを検討して、紹介を続けます。
注:このチュートリアルでは、Ubuntuおよびその他のLinuxオペレーティングシステムにあるsed
のGNUバージョンを使用します。 macOSを使用している場合は、さまざまなオプションと引数を持つBSDバージョンがあります。 brew install gnu-sed
を使用して、sed
のGNUバージョンをHomebrewとともにインストールできます。
インタラクティブターミナルを起動します!
このチュートリアルを完了するには、操作するいくつかのファイルが必要です。これは、最初のチュートリアルから持っている必要があります。 それらがない場合は、次のコマンドを使用して再作成できます。
cd cp /usr/share/common-licenses/BSD . echo "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..." > song.txt
さらに、このチュートリアルでは GPL 3ライセンスを使用するため、そのファイルもコピーします。
cp /usr/share/common-licenses/GPL-3 .
お持ちでない場合は、curl
でダウンロードできます。
curl -o GPL-3 https://www.gnu.org/licenses/gpl-3.0.txt
ファイルができたので、sed
を複数のコマンドで使用して調べます。
複数の編集シーケンスの提供
sed
に同時に複数のコマンドを渡したい場合がかなりあります。 これを実現する方法はいくつかあります。
sed
は標準の入力と出力で動作するため、パイプラインを介してsed
へのさまざまな呼び出しをつなぎ合わせることができます。 このコマンドを実行して、単語and
をアパーサンド(&
)に置き換え、単語people
をhorses
に置き換えます。
sed 's/and/\&/' song.txt | sed 's/people/horses/'
「&」は「完全に一致したパターン」を意味するため、エスケープする必要があることに注意してください。sed
):
次の出力が表示されます。
Outputthis 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
に文字列化できます。 これは、前のコマンドを書き直す方法です。
sed -e 's/and/\&/' -e 's/people/horses/' song.txt
コマンドをつなぎ合わせる別の方法は、セミコロン文字(;
)を使用して個別のコマンドを区切ることです。 これは前の例と同じように機能しますが、「-e
」は必須ではありません。
sed 's/and/\&/;s/people/horses/' song.txt
-e
構成を使用する場合、コマンドごとに個別の単一引用符グループが必要であることに注意してください。 ただし、コマンドをセミコロンで区切る場合、すべてのコマンドは1つの引用符で囲まれたコマンド文字列内に配置されます。 複数のコマンドを表現するこれらの2つの方法は便利ですが、以前の配管技術が依然として必要な場合があります。
=
演算子について考えてみます。 この演算子は、既存の各行の間の新しい行に行番号を挿入します。 出力は次のようになります。
sed '=' song.txt
表示される出力は次のとおりです。
Output1 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
コマンドを見てみましょう。このコマンドは、デフォルトで各行の間に空白行を入力します(これは実際にはもっと複雑ですが、後で調べます)。
sed 'G' song.txt
結果は次のとおりです。
Outputthis 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つのコマンドを組み合わせると、通常の各行と行番号行の間にスペースが必要になる場合があります。
sed '=;G' song.txt
ただし、何か違うものがあります。
Output1 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番目のテキストの単純なストリームとして扱います。
sed '=' song.txt | sed 'G'
これで、期待していた結果が表示されます。
Output1 this is the song that never ends 2 yes, it goes on and on, my friend 3 some people started singing it . . . . . .
特に複数のコマンドをつなぎ合わせていて、出力が期待したものと異なる場合は、一部のコマンドがこのように動作することに注意してください。
高度なアドレス指定
sed
のアドレス指定可能なコマンドの利点の1つは、正規表現を選択基準として使用できることです。 これは、前に見たように、既知のライン値での操作に制限されないことを意味します。
sed '1,3s/.*/Hello/' song.txt
OutputHello Hello Hello not knowing what it was and they'll continue singing it forever just because...
代わりに、正規表現を使用して、特定のパターンを含む行のみに一致させることができます。 これを行うには、コマンド文字列を指定する前に、2つのスラッシュ(/)の間に一致パターンを配置します。
sed '/singing/s/it/& loudly/' song.txt
Outputthis 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行目はパターンと一致しないため、変更されていないことに注意してください。
アドレス指定の式は、任意に複雑にすることができます。 これにより、コマンドの実行に大きな柔軟性がもたらされます。
これは複雑な例ではありませんが、正規表現を使用して他のコマンドのアドレスを生成する方法を示しています。 次のコマンドは、空白行(行の先頭の直後に行の終わりが続く)と一致し、それらを削除コマンドに渡します。
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
というファイルを作成します。
echo "This is an input file START this is the text we don't want END This is additional text" > inputfile
次に、sed
を使用して、START
とEND
の間のコンテンツを削除します。
sed '/^START$/,/^END$/d' inputfile
次の出力が表示されます。
This is an input file This is additional text
ただし、これにより、最初のSTART
から最初のEND
までのすべてが削除され、別のSTART
マーカーが見つかった場合は削除が再開されます。
アドレスを反転したい場合(がパターンと一致しない行で操作する)、感嘆符(!
)でパターンをたどることができます。
たとえば、次のコマンドを使用して、空白ではない行を削除できます(それほど有用ではありませんが、単なる例です)。
sed '/^$/!d' GPL-3
sed
はデフォルトで行を出力するため、これにより大きな空白の出力が発生します。
Output
アドレスは、反転するために複雑な式である必要はありません。 反転は、通常の番号付きアドレスでも同じように機能します。
ホールドバッファの使用
sed
の複数行対応の編集を実行する機能を向上させる機能の1つは、いわゆる「ホールドバッファー」です。 ホールドバッファは、特定のコマンドで変更できる一時ストレージの領域です。
この余分なバッファが存在するということは、他の行で作業しているときに行を保存し、必要に応じて各バッファを操作できることを意味します。
保持バッファに影響を与えるコマンドは次のとおりです。
- h :現在のパターンバッファー(現在一致して作業している行)を保持バッファーにコピーします(これにより、保持バッファーの以前の内容が消去されます)。
- H :現在のパターンバッファーを現在の保持パターンの最後に改行(\ n)文字で区切って追加します。
- g :現在の保持バッファーを現在のパターンバッファーにコピーします。 前のパターンバッファが消去されます。
- G :現在の保持パターンを現在のパターンバッファーの最後に改行(\ n)文字で区切って追加します。
- x :現在のパターンと保持バッファーを入れ替えます。
保持バッファの内容は、何らかの方法でパターンバッファに移動されるまで操作できません。
複雑な例を使ってこのアイデアを調べてみましょう。
これは、隣接するラインを結合する方法の手順の例です(sed
には、実際には、これの多くを処理する組み込みのコマンドがあります。 N
コマンドは、現在の行に次の行を追加します。 練習のために、難しい方法で物事を行うつもりです):
sed -n '1~2h;2~2{H;g;s/\n/ /;p}' song.txt
表示される出力は次のとおりです。
Outputthis 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
コマンドを使用するとこれが大幅に短縮されます。 次のコマンドは、今見たのと同じ結果を生成します。
sed -n 'N;s/\n/ /p' song.txt
スクリプトの使用
より複雑なコマンドを使い始めると、テキストエディタでそれらを作成すると役立つ場合があります。 これは、単一のターゲットに適用するコマンドが多数ある場合にも役立ちます。
たとえば、プレーンテキストでメッセージを作成したいが、テキストを使用する前に一連の標準化されたフォーマットを実行する必要がある場合は、sed
スクリプトが役立ちます。
sed
呼び出しの各セットを入力する代わりに、コマンドをスクリプトに入れて、sed
の引数として指定できます。 sed
スクリプトは、生のsed
コマンド(通常は一重引用符で囲まれた文字の間の部分)のリストです。
これを試すには、次の内容のsed_script
という名前の新しいファイルを作成します。
echo "s/this/that/g s/people/horses/g 1,5s/it/that/g" > sed_script
ファイルを保存して、エディターを終了します。
次に、-f
スイッチを使用して、ファイルを使用するようにsed
に指示します。
sed -f sed_script song.txt
結果は次のようになります。
Outputthat 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
に慣れているほど、長期的には必要な作業が少なくなります。