- Linuxのsedコマンドは、ファイルとストリーム内のテキストを操作するために使用される、インターフェイスのない強力なテキストエディタです。
- sedは、ファイルとストリーム内のテキストを選択、置換、追加、削除、変更でき、作業中に従う指示を提供します。
- sedは、パターンマッチングとテキスト選択に正規表現を多用しており、sedを効果的に使用するには正規表現に精通していることが重要です。
気が狂っているように聞こえるかもしれませんが、Linuxのsed
コマンドは、インターフェイスのないテキストエディタです。コマンドラインから使用して、ファイルとストリーム内のテキストを操作できます。その威力を活用する方法を紹介します。
sedの力
sed
コマンドは、チェスに似ています。基本を学ぶのに1時間、習得するのに一生かかります(または、少なくとも多くの練習が必要です)。sed
の機能の主要なカテゴリのそれぞれで、オープニングギャンビットの選択を紹介します。
sed
は、パイプ入力またはテキストファイルで機能するストリームエディタです。ただし、対話型のテキストエディタインターフェイスはありません。その代わりに、テキストを処理するときに従う指示を提供します。これはすべて、Bashやその他のコマンドラインシェルで機能します。
sed
では、次のすべてを実行できます。
- テキストを選択する
- テキストを置換する
- テキストに行を追加する
- テキストから行を削除する
- 元のファイルを修正(または保持)する
最も簡潔な(そして最もアクセスしやすい)sed
コマンドを生成するのではなく、概念を導入して実証するために例を構成しました。ただし、sed
のパターンマッチングとテキスト選択の機能は、正規表現(regexes)に大きく依存しています。sed
を最大限に活用するには、これらに精通している必要があります。
簡単な例
まず、echo
を使用してテキストをパイプを介してsed
に送信し、sed
にテキストの一部を置換させます。これを行うには、次のように入力します。
echo howtogonk | sed 's/gonk/geek/'
echo
コマンドは「howtogonk」をsed
に送信し、単純な置換ルール(「s」は置換を表します)が適用されます。sed
は入力テキストで最初の文字列の出現を検索し、一致するものをすべて2番目の文字列で置き換えます。
文字列「gonk」は「geek」に置き換えられ、新しい文字列が端末ウィンドウに印刷されます。
置換は、おそらくsed
の最も一般的な使用法です。しかし、置換をさらに詳しく調べる前に、テキストを選択して一致させる方法を知る必要があります。
テキストを選択する
例のためにテキストファイルが必要です。サミュエル・テイラー・コウルリッジの叙事詩「老水夫の唄」からいくつかの節を選択したファイルを使用します。
less
を使用して確認するには、次のように入力します。
less coleridge.txt
ファイルからいくつかの行を選択するには、選択する範囲の開始行と終了行を指定します。1つの数字はその1行を選択します。
1行目から4行目を抽出するには、このコマンドを入力します。
sed -n '1,4p' coleridge.txt
1
と4
の間にコンマがあることに注意してください。p
は「一致する行を印刷」を意味します。デフォルトでは、sed
はすべての行を印刷します。一致する行が2回印刷された状態で、ファイル内のすべてのテキストが表示されます。これを防ぐために、-n
(静か)オプションを使用して、一致しないテキストを抑制します。
行番号を変更して、別の節を選択できます。以下に示します。
sed -n '6,9p' coleridge.txt
-e
(式)オプションを使用して、複数の選択を行うことができます。2つの式を使用すると、次のように2つの節を選択できます。
sed -n -e '1,4p' -e '31,34p' coleridge.txt
2番目の式の最初の数字を減らすと、2つの節の間に空白を挿入できます。次のように入力します。
sed -n -e '1,4p' -e '30,34p' coleridge.txt
開始行を選択し、sed
にファイルを進めて交互の行、5行ごとに印刷したり、任意の数の行をスキップしたりすることもできます。コマンドは、範囲を選択するために上記で使用したものに似ています。ただし、今回はコンマではなくチルダ(~
)を使用して数字を区切ります。
最初の数字は開始行を示します。2番目の数字は、sed
に開始行の後に表示する行を伝えます。数字2は2行目、3は3行目、などを意味します。
次のように入力します。
sed -n '1~2p' coleridge.txt
探しているテキストがファイルのどこに存在するか常に判明するとは限らないため、行番号が常に役立つわけではありません。ただし、一致するテキストパターンを含む行を選択するためにsed
を使用することもできます。たとえば、「And」で始まるすべての行を抽出してみましょう。
キャレット(^
)は行の開始を表します。検索語をスラッシュ(/
)で囲みます。また、「And」の後にスペースを含めることで、「Android」などの単語が結果に含まれないようにします。
最初はsed
のスクリプトを読むのが少し難しい場合があります。/p
は、上で使用したコマンドと同様に「印刷」を意味します。ただし、次のコマンドでは、スラッシュが前に付いています。
sed -n '/^And /p' coleridge.txt
「And 」で始まる3行がファイルから抽出されて表示されます。
置換を行う
最初の例では、sed
の置換の基本的な形式を次のように示しました。
echo howtogonk | sed 's/gonk/geek/'
s
はsed
にこれが置換であることを伝えます。1番目の文字列は検索パターンであり、2番目は一致するテキストを置き換えるテキストです。もちろん、Linuxのすべてのものと同様に、詳細は複雑です。
次のコマンドを入力して、「day」のすべての出現箇所を「week」に変更し、船乗りとアホウドリにさらに絆を深める時間を与えます。
sed -n 's/day/week/p' coleridge.txt
最初の行では、「day」の2番目の出現のみが変更されます。これは、sed
が1行につき最初のマッチの後に停止するためです。各行のすべてのマッチが処理されるように、グローバル検索を実行するには、次のように式の末尾に「g」を追加する必要があります。
sed -n 's/day/week/gp' coleridge.txt
これは、最初の行の4つのうち3つに一致します。最初の単語は「Day」であり、sed
は大文字と小文字を区別するため、このインスタンスは「day」と同じとはみなされません。
式の末尾にi
を追加して大文字と小文字を区別しないことを示すコマンドを入力します。
sed -n 's/day/week/gip' coleridge.txt
これは機能しますが、すべてに対して大文字と小文字を区別しないようにする必要はない場合があります。そのような場合、正規表現グループを使用して、パターンに固有の大文字と小文字の区別をなくすことができます。
たとえば、文字を角カッコ([]
)で囲むと、「この文字のリストの任意の文字」として解釈されます。
次のコマンドを入力し、「Day」と「day」の両方に一致するように、グループに「D」と「d」を含めます。
sed -n 's/[Dd]ay/week/gp' coleridge.txt
また、置換をファイルの一部に制限することもできます。ファイルの最初の節に奇妙なスペースが含まれているとします。次のよく知られたコマンドを使用して、最初の節を確認できます。
sed -n '1,4p' coleridge.txt
2つのスペースを検索して1つのスペースに置き換えます。これはグローバルに行うので、アクションは行全体で繰り返されます。明確にするために、検索パターンはスペース、スペースのアスタリスク(*
)、置換文字列は1つのスペースです。1,4
は置換をファイルの最初の4行に制限します。
次のコマンドにすべてまとめます。
sed -n '1,4 s/ */ /gp' coleridge.txt
これはうまく機能します!ここでは、検索パターンが重要です。アスタリスク(*
)は、前の文字のゼロ個以上を表します。これはスペースです。したがって、検索パターンは1つ以上のスペースの文字列を検索しています。
単一のスペースを複数のスペースのシーケンスに置き換えると、ファイルは通常のスペースに戻り、各単語の間に1つのスペースが配置されます。これにより、場合によっては単一のスペースが単一のスペースに置き換えられますが、これは何にも悪影響を及ぼしません。それでも、目的の結果は得られます。
次のコマンドを入力して、検索パターンを1つのスペースに減らすと、なぜ2つのスペースを含める必要があるのかがすぐにわかります。
sed -n '1,4 s/ */ /gp' coleridge.txt
アスタリスクは前の文字のゼロ個以上と一致するため、スペースではない各文字を「ゼロスペース」と見なし、それに置換を適用します。
ただし、検索パターンに2つのスペースを含めると、sed
は置換を適用する前に少なくとも1つのスペース文字を見つける必要があります。これにより、スペース以外の文字がそのまま残ります。
前に使用した-e
(式)を使用して、2つ以上の置換を同時に実行できるようにします。
sed -n -e 's/motion/flutter/gip' -e 's/ocean/gutter/gip' coleridge.txt
2つの式をセミコロン(;
)で区切ると、同じ結果が得られます。
sed -n 's/motion/flutter/gip;s/ocean/gutter/gip' coleridge.txt
次のコマンドで「day」を「week」に置き換えたとき、「well a-day」という式の「day」のインスタンスも置き換えられました。
sed -n 's/[Dd]ay/week/gp' coleridge.txt
これを防ぐには、別のパターンに一致する行でのみ置換を試行できます。コマンドを変更して開始時に検索パターンを設定すると、そのパターンに一致する行でのみ操作を考慮します。
マッチングパターンを単語「after」にするには、次のように入力します。
sed -n '/after/ s/[Dd]ay/week/gp' coleridge.txt
これにより、目的の応答が得られます。
より複雑な置換
コウルリッジを休憩させ、sed
を使用してetc/passwd
ファイルから名前を抽出しましょう。
これを行うためのより短い方法があります(それについては後で詳しく説明します)。ここでは、別の概念を示すために長い方法を使用します。検索パターンの各一致項目(部分式と呼ばれる)には番号を付けることができます(最大9項目まで)。その後、これらの番号をsed
コマンドで使用して、特定の部分式を参照できます。
これを行うには、部分式を角カッコ(()
)で囲む必要があります。また、角カッコの前にバックスラッシュ(\
)を付けて、通常の文字として扱われないようにする必要があります。
これを行うには、次のように入力します。
sed 's/\([^:]*\).*/\1/' /etc/passwd
これを分解してみましょう。
sed 's/
:sed
コマンドと置換式の先頭。\(
:バックスラッシュ(\
)が前に付いた部分式を囲む開き括弧((
)。[^:]*
:検索語の最初の部分式には、角かっこで囲まれたグループが含まれています。グループ内で使用されるキャレット(^
)は「not」を意味します。グループとは、コロン(:
)ではない任意の文字が一致として受け入れられることを意味します。\)
:バックスラッシュ(\
)が前に付いた閉じ括弧()
)。.*
:この2番目の検索部分式は「任意の文字とそれらの任意の個数」を意味します。/\1
:式の置換部分には、バックスラッシュ(\
)が前に付いた1
が含まれています。これは、最初の部分式と一致するテキストを表します。/'
:閉じ括弧(/
)と一重引用符('
)でsed
コマンドを終了します。
つまり、コロン(:
)を含まない任意の文字列を探し、それが一致するテキストの最初のインスタンスになります。次に、その行の他のものを検索します。これは、一致するテキストの2番目のインスタンスになります。行全体を、最初の部分式と一致したテキストで置き換えます。
/etc/passwd
ファイルの各行は、コロンで終わるユーザー名で始まります。最初のコロンまですべてを一致させ、その値をその行全体に置き換えます。したがって、ユーザー名を分離しました。
次に、2番目の部分式を角カッコ(()
)で囲んで、番号で参照できるようにします。また、\1
を\2
に置き換えます。これで、コマンドは最初のコロン(:
)から行末までのすべてをその行全体に置き換えます。
次のように入力します。
sed 's/\([^:]*\)\(.*\)/\2/' /etc/passwd
これらの小さな変更により、コマンドの意味が反転し、ユーザー名以外のすべてを取得します。
それでは、これを行うための迅速かつ簡単な方法を見てみましょう。
検索語は最初のコロン(:
)から行末までです。置換式が空(//
)なので、一致したテキストを何も置き換えることはありません。
したがって、次のコマンドを入力して、最初のコロン(:
)から行末までのすべてを切り取り、ユーザー名だけを残します。
sed 's/:.*//" /etc/passwd端末ウィンドウのnew_geeks.txt" data-img-url="https://static1.howtogeekimages.com/wordpress/wp-content/uploads/2020/04/29.png" />
sedをすべて使用する
お気づきのように、sed
のこのクイック入門書でさえかなり長いです。このコマンドには多くの機能があり、さらに多くのことができます。
しかし、これらの基本的な概念が、学習を続ける際に構築できる強固な基盤を提供してくれることを願っています。
コメントする