Linuxコマンド - sed

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動

概要

sedコマンドとは、与えられた文字列をルールに従って変換するコマンドである。
例えば、文字列の置換や行の削除といった処理が行う。

変換に利用できるルールにおいて、下表のような条件式が利用できる。
例えば、文字列を挿入したい場合は、aiの後に挿入する文字列を指定する。
文字列を置換したい場合は、s/置換ルール/置換文字/と実行する。

置換ルールの最初に数値を指定すると、指定した行のみが処理される。
例えば、3dと指定すると、3行目が削除される。

sedコマンドで実際に変換を行う場合は、変換処理内容は-eオプションを指定した後に記述する。
また、sedコマンドに指定したファイルの内容を処理する。
例えば、test.txt内にある"Linux"を"リナックス"に置換する場合は、次のように実行する。

sed -e "s/Linux/リナックス/g" test.txt 


結果は標準出力に表示される。
もし、ファイルに保存する場合はリダイレクトを利用する。

また、-fオプションで変換手順を記載したスクリプトファイルを指定できる。その時、指定したファイルの内容に従って処理される。


sedのインストール

パッケージ管理システムからインストール

多くのLinuxディストリビューションでは、最小インストールでsedがインストールされている。
もし、何らかの理由でインストールされていない場合は、パッケージ管理システムからsedインストールすることができる。

sudo zypper install sed


ソースコードからインストール

手動でsedをインストールする場合、ソースコードからsedをインストールする。

GNUソフトウェアの公式Webサイトにアクセスして、sedのソースコードをダウンロードする。
ダウンロードしたファイルを解凍する。

tar xf sed-<バージョン>.tar.xz
cd sed-<バージョン>


sedをビルドおよびインストールする。

mkdir build && cd build

../configure --prefix=<sedのインストールディレクトリ>
make -j $(nproc)
make install


~/.profileファイル等に、環境変数PATHを追記する。

vi ~/.profile


 # ~/.profileファイル
 
 export PATH="/<sedのインストールディレクトリ>/bin:$PATH"



構文

sed <オプション> <対象ファイル>


オプション 説明
-e <スクリプト名> 指定したスクリプト(条件式)で変換処理を行う。
-f <ファイル名> 指定したファイルに記述されているコマンドやスクリプトに従って処理を行う。
r 指定したファイルに記述されているコマンドやスクリプトに従って処理を行う。



パターン・スペースとホールド・スペース

sedコマンドでは、処理を行う対象の文字列を一時的に保存しておく必要がある。
この保存スペースのことをパターン・スペースと呼ぶ。
例えば、1行目を処理する時には、1行目の内容がパターン・スペースに保存される。その後、パターン・スペースにある文字列に対して置換などの処理が行われる。

ホールド・スペースとは、パターン・スペースのサブとして使われる保存領域である。
例えば、パターン・スペースにある文字列を後の処理で利用する場合等は、一度ホールド・スペースに移動しておく。
他の処理を行った後に、ホールド・スペースからパターン・スペースに戻せば、以前の処理の続きが行うことができる。

パターン・スペースの文字列をホールド・スペースにコピーする場合はh
ホールド・スペースの文字列をパターン・スペースにコピーする場合はg
パターン・スペースとホールド・スペースを入れ替える場合はxを実行すればよい。


sedコマンドの条件式

条件式 説明
行数 処理する行数を指定する
行数,行数 指定した行数間の文字列を処理する。
$を指定すると最後の行を表せる。
/文字列/ 指定した文字列が現れる行を処理する。
先頭に^を付けると、指定した文字列から始まる行、末尾に$を付けると指定した文字列で終わる行が対象になる。
行数の範囲指定でも利用できる。
:ラベル bおよびtコマンド用のラベル
#コメント コメント
{..} 括弧内をブロックとして扱う。
= 現在の行番号を表示する。
a <文字列> 文字列を追加する。ただし、改行をする場合は、直前に\を付ける。
i <文字列> 文字列を挿入する。ただし、改行をする場合は、直前に\を付ける。
q 処理を中断して、sedコマンドを終了する。
r <ファイル名> 指定したファイルを読み出して追加する。
b <ラベル> 指定したラベルに移動する。
t <ラベル> s///が成功した場合、指定したラベルに移動する。
c <文字列> 選択している行を文字列に置換する。ただし、改行をする場合は、直前に\を付ける。
d パターン・スペースを削除する。
D パターン・スペース内の最初の改行までを削除する。
h パターン・スペースをホールド・スペースにコピーする。
H パターン・スペースをホールド・スペースに追加する。
g ホールド・スペースをパターン・スペースにコピーする。
G ホールド・スペースをパターン・スペースに追加する。
x ホールド・スペースとパターン・スペースを入れ替える。
n 次の行をパターン・スペースに読み込む。
N 次の行をパターン・スペースに追加する。
p 現在のパターン・スペースを表示する。
P 現在のパターン・スペースの最初に現われる改行までを表示する。
w <ファイル名> 現在のパターン・スペースを指定したファイルに書き込む。
s/置換条件/置換文字/ 置換条件を置換文字に変換する。
最後にgを付けた場合は、置換条件に当てはまる全ての文字列が置換される。
y/変換対象の文字/変換文字/ 変換対象の文字を変換文字に変換する。



デリミタ

sedコマンドには、置換のデリミタ (区切り文字) が複数存在する。
機能的には同じ結果をもたらす。

デリミタとしては他にも :@#などの文字を使用することができる。

# /を区切り文字として扱う場合
sed -i "s/<lastmod>.*</lastmod>/<lastmod>${current_date}</lastmod>/g" hoge.xml

# |を区切り文字として扱う場合
sed -i "s|<lastmod>.*</lastmod>|<lastmod>${current_date}</lastmod>|g" hoge.xml


これらの違いが重要になる理由を以下に示す。

  • 可読性
    パスやURLを含む文字列を扱う場合、/を含むことが多いため、|を使用すると読みやすくなることがある。
  • エスケープの必要性
    /をデリミタとして使用する場合、置換対象やパターン内に/が含まれている時、それをエスケープする必要がある。
    |を使用すると、/をエスケープする必要がない。


上記では、XMLタグを扱っているため、どちらを使用しても問題ない。
しかし、より複雑なパターンや/ (スラッシュ) を含む文字列を扱う場合は、| (バーティカルバー) を使用する方が便利な場合がある。


使用例

テキストファイルの5~10行目を削除する。

sed -i -e "5,10d" test.txt 


テキストファイル内の"Nikkei Linux"を"日経Linux"に変換する。

sed -i -e "s/Nikkei Linux/日経Linux/g" test.txt 


"Error"という文字列がある行に対して、"### Check Line ###"という新しい行を追加する。

sed -i -e "/Error/i #### Check Line ###" test.txt


複数の命令を1度に実行する。

# "baseball"を"swimming"に置換した後、"rugby"を含む行を削除
sed -i -e 's/baseball/swimming/' -i -e '/rugby/d' test.txt


複数のファイルを一括置換する。

# 複数のファイル内の“apple”を“orange”に置換
sed -i 's/apple/orange/' test1.txt test2.txt test3.txt



正規表現

sedコマンドは、多くの正規表現を使用することができる。
ただし、sedコマンドの正規表現の記述方法は、他のプログラム言語の正規表現はやや異なっているので注意する。

下表に、sedコマンドで使用できる正規表現を示す。
併せて、grepコマンドとawkコマンドの正規表現も記載する。

grep sed awk 意味
. . . 任意の1文字
* * * 直前の1文字または1パターンの0回以上の繰り返し
^ ^ ^ 行の先頭
$ $ $ 行の末尾
\( \) \( \) () パターンのグループ化
\1 \2 \3 \1 \2 \3 後方参照
[ ] [ ] [ ] 括弧内の任意の1文字
\{n\} \{n\} {n} 直前の1文字または1パターンのn回の繰り返し
\{n, \} \{n, \} {n, } 直前の1文字または1パターンのn回以上の繰り返し
\{n, m\} \{n, m\} {n, m} 直前の1文字または1パターンのn回以上かつm回以下の繰り返し
\+ \+ + 直前の1文字あるいは1パターンの1回以上の繰り返し
\? ? 直前の1文字あるいは1パターンの0回または1回だけ出現
\| \| | 2 パターンのうちどちら片方
.* 空文字("")を含む任意の文字列
[aA0] aもしくはAもしくは0
[^aA0] aでもAでも0でもない文字
[a-z] aからzまでのいずれかの文字
^$ 空行



sedコマンドを使用したフィルタリング

フィルタとは

フィルタとは標準入力からデータを受け取り、そのデータを加工した上で標準出力に出力する機能のことである。
この機能には、主に、sed、awk、tr、grep等のコマンドが使用され、それらのコマンドに|(パイプ)でデータを受け渡すことでフィルタ機能を実現する。
(例: パイプを使用して不必要な文字列を消去する処理や適切な位置に文字列を付加する処理)

以下のような処理には、フィルタを使用すると効率的に作業ができる。

  • コマンドの実行結果から、次のコマンドのパラメータを生成する。
  • あるファイルを決まったパターンで編集する。
  • 膨大な文字数のログファイル内から必要な情報のみを抜き出す。


パイプでフィルタに加工するデータを受け渡し、目的とする文字列を抽出するフィルタリングを行う。
フィルタをパイプで複数連結することで、より複雑なフィルタリング処理を実現することができる。

command | filter
command | filter1 | filter2
command | filter1 | ... | filterN


文字列Aを文字列Bに置換する

sedコマンドは様々な機能を持つコマンドであるが、主に、文字列の置換処理に利用されるコマンドである。

置換処理を行う場合、置換対象と置換後の文字列を指定してコマンドを実行する。
置換対象の指定には、正規表現を使用することも可能である。
ただし、一部の正規表現は使用できない。また、sedのバージョン等により、使用できる正規表現も異なる。

各行の最初に一致した文字列のみ置換する。

sed -e 's/パターン1/パターン2/'  # 各行の最初に一致したパターン1をパターン2に置換する


gの指定が無い場合、各行の最初に一致した文字列のみが置換対象となる。
同一行内に複数の一致があった場合でも、2つめ以降の一致した文字列は置換されない。

echo "hogehoge" | sed -e 's/hoge/fuga/'  # 文字列"hogehoge"の"hoge"を"fuga"に置換する
                                         # 実際に置換されるのは、先頭の"hoge"のみ
fugahoge


一致したすべての文字列を置換するには、g(globally)を指定する。

sed -e 's/パターン1/パターン2/g'  # sedコマンドの置換パターンにgを指定する


gを指定すると各行の最初に一致した文字列のみではなく、すべての一致する文字列を置換対象とする。

echo "hogehoge" | sed -e 's/hoge/fuga/g'  # gを指定して実行することで、全ての"hoge"が"fuga"に置換される
fugafuga


アルファベットの大文字小文字を区別しない。

sed -e 's/パターン1/パターン2/i'  # iを指定することで大文字小文字の区別を行わない


iを指定する場合、アルファベットの大文字小文字を区別しない置換処理を行う。
例えば、パターン1に"a"を指定する時、"a"と"A"が置換対象となる。

echo "HogeHoge" | sed -e 's/hoge/fuga/i'  # iを指定することで、大文字小文字を区別することなく置換処理が行われる
fugaHoge

echo "HogeHoge" | sed -e 's/hoge/fuga/gi'  # 上記のように、iとgを同時に指定することもできる
fugafuga


複数パターンの置換を連続して行うには、-eオプションで複数の置換パターンを連結して指定する。

sed -e 's/パターン1/パターン2/' -e 's/パターン3/パターン4/'


以下の例では、各行最初に一致したパターン1をパターン2に置換後、
さらにパターン3をパターン4に置換するといった複数の置換を連続して実行している。

echo "hogehoge fugafuga" | sed -e 's/hoge/foo/g' -e 's/fuga/bar/g'  # "hoge"を"foo"に置換した後、さらに、"fuga"を"bar"に置換する
foofoo barbar

echo "hogehoge fugafuga" | sed -e 's/hoge/foo/g' -e 's/fuga/bar/g' -e 's/ /-/g'  # 上記に加えて、スペースをハイフンに置換する
foofoo-barbar

echo "hoge" | sed -e 's/hoge/fuga/' -e 's/fuga/foo/' -e 's/foo/bar/'  # "hoge"を次々に置換して、最終的に"bar"にしている
bar


パターン指定の区切り文字を変更する。
パターン指定の区切り文字には、任意の文字を使用することができる。

sedコマンドは、sの直後に指定した文字を区切り文字として認識するため、使用する区切り文字は/(スラッシュ)でなくともよい。
特に /自体がパターンに含まれる場合は、/の代わりに%や|等を区切り文字に使用すると、/をエスケープする必要がなくなる。
これは、大変便利なテクニックであるため、是非覚えておくこと。

sed -e 's%パターン1%パターン2%'
sed -e 's|パターン1|パターン2|'
sed -e 's:パターン1:パターン2:'


以下の例では、/を区切り文字にする場合、/がパターンに含まれる場合はエスケープする必要がある。
これを、/以外の区切り文字に変更して実行している。(可読性の面で、大変有利である)

echo "hoge/hoge" | sed -e 's/hoge\/hoge/fuga\/fuga/'
fuga/fuga

echo "hoge/hoge" | sed -e 's%hoge/hoge%fuga/fuga%'
fuga/fuga

echo "hoge/hoge" | sed -e 's|hoge/hoge|fuga/fuga|'
fuga/fuga

echo "hoge/hoge" | sed -e 's:hoge/hoge:fuga/fuga:'
fuga/fuga


単一置換パターン指定であれば、-eオプションは省略できる。

sed 's/パターン1/パターン2/'


複数の置換パターンを指定しない場合は、-eオプションは省略できる。
ただし、省略しても問題なく機能するが、後から他のパターンを追加するような場合もあるので、常に指定することを推奨する。

echo "hoge" | sed 's/hoge/fuga/'
fuga


文字列の削除

特定の文字列を削除するには、置換後のパターンに空文字を指定する。
これにより、置換対象パターンと一致する文字列は空文字に置換されるため、結果的に削除と同等の処理となる。

各行の最初に一致したパターンを削除する。

sed -e 's/パターン//'


全てのパターンを削除する。

sed -e 's/パターン//g'  # 置換後の文字列を指定しないことで削除処理になる


文字列の削除も置換処理と同じなので、通常の置換処理と使い方は同じである。

echo "hoge-fuga foo-bar" | sed -e 's/-//'  # gを指定していないため、最初に一致した文字のみ削除される
hogefuga foo-bar

echo "hoge-fuga foo-bar" | sed -e 's/-//g'  # gを指定すると、全ての一致する文字列が削除される
hogefuga foobar



正規表現を使用した文字列置換

置換対象パターンの指定には、一部の正規表現を使用することもできる。
使用可能な正規表現は、sedのバージョン等により異なる場合がある。

aからeまでのいずれかの文字をXに置換する。

echo "abcdefghij" | sed -e 's/[a-e]/X/g'
XXXXXfghij


数字以外を削除する。

echo "I am 20 years old." | sed -e 's/[^0-9]//g'
20


行頭に文字列を追加するには、行頭を表す^(キャレット)を追加する文字列に置換する。

echo "Hello World" | sed -e 's/^/>>>/g'
>>>Hello World


行末に文字列を追加するには、行末を表す$を追加する文字列に置換する。

echo "Hello World" | sed -e 's/$/ !!!/g'
Hello World !!!


連続する複数のスペースを1つにまとめる。
連続する複数のスペースは、 *で表される。

*(アスタリスク)は直前の文字の0〜N個の繰り返しであるため、 *では0個のスペースも置換対象とみなされる。
したがって、連続する複数のスペースを表すには、"1個のスペース + 0〜N個のスペース"で *となる。

echo "hello     world" | sed -e 's/  */ /'
hello world


GNU sed(Linuxのsed)では、 \+で、1個以上の連続するスペースを表現することができる。

echo "hello     world" | sed -e 's/ \+/ /'
hello world


特定の位置の文字列を切り出す

例えば、5文字目から10文字目までを切り出す場合や"ABC"の後に続く3文字を切り出す場合等、
特定の条件に一致する部分的な文字列のみを切り出す。

sed -e 's/パターンA\(切り出し対象パターン\)パターンB/\1/'  # 文字列を正規表現化して、切り出す部分をエスケープした()で囲む


全体のパターン(パターンA + 対象パターン + パターンB)に一致した文字列のうち、
()で囲んだ対象パターンに一致する部分を、\1 を使用することで切り出すことができる。

また、()で囲む部分を増やすことにより切り出す文字列を複数指定でき、1番目の括弧は\1、2番目の括弧は\2といったように、
()の順番に対応した番号を指定して切り出すことができる。

なお、切り出し対象を指定する括弧は、\( \)のようにエスケープする必要がある。

echo "ABC123DEF456" | sed -e 's/...\(...\).*/\1/'  # .(ドット)は任意の1文字を表すため、<cooe>...</coe>は任意の3文字を表す
123

echo "ABC123DEF456" | sed -e 's/...\(...\)...\(...\)/\1 \2/'
123 456

echo "ABC123DEF456" | sed -e 's/...\(...\)/\1 /'
123 DEF456


sedコマンドによる文字列の切り出しは、パターンに一致した文字列を括弧の中の文字列で置換する。
そのため、上記の3つ目の例のように、パターンに一致しなかった部分はそのまま出力される。

同様に、exprコマンドでも文字列を切り出すことができる。

expr "文字列" : "パターンA\(対象パターン\)パターンB"  # 文字列を正規表現化して、切り出す部分をエスケープした()で囲む


exprコマンドでは1度に複数の部分を切り出すことはできない。(切り出されるのは最初の括弧の部分のみ)
sedコマンドと同様に、括弧はエスケープする必要がある。
ただし、sedコマンドとは異なり、パターンに一致しなかった部分は出力されない。

expr "ABC123DEF456" : "...\(...\)"  # パターンに一致しない部分DEF456は出力されない
123

expr "ABC123DEF456" : "...\(...\)...\(...\)"  # 1度に複数の部分を切り出すことはできない
123


制御文字を削除する

Windows上でテキストファイルを作成して、改行コードをLFに変換せずにCR + LFのままLinuxへ転送するといったミスがよくある。
この時、転送されたファイルをLinux上でvi等を使用して開くと、行末に^Mが表示されていることがある。

制御文字をsedコマンドで削除する場合、制御文字を指定することは少し煩雑である。
削除対象となる制御文字は、sedコマンドに^M等と直接入力しても削除することができない。

例えば、制御文字である^Mを入力するには、 [Ctrl] + [V]、[Ctrl] + [M]と連続して入力する。

以下の例では、削除対象となる制御文字の^Mが含まれたテキストファイルをviで開いている。
hoge、piyo、fugaは通常の文字列、行末の^Mが削除対象となる制御文字となっている。

vi CRLF.txt

hoge ^M
piyo ^M
fuga ^M


sedコマンドの置換対象の文字列の入力において、[Ctrl] + [V]、[Ctrl] + [M]と入力する。

sed -e 's/^M//g' CRLF.txt > LF.txt  # "^"は制御文字であるため、エスケープは不要


変数を使用した文字列置換

置換パターンの指定には、変数の値を使用することができる。

sed -e "s/${変数名}/置換後パターン/"
sed -e "s/置換対象パターン/${変数名}/"
sed -e "s/$VAR1/$VAR2/"


VAR="hoge"

echo "hoge piyo fuga" | sed -e "s/${VAR}/foo/"  # 変数VARの値(hoge)をfooに置換
foo piyo fuga

echo "hoge piyo fuga" | sed -e "s/fuga/$VAR/"  #↑変数VARの値(hoge)が置換パターンに使用される
hoge piyo hoge


行を指定した置換

sedコマンドは、行番号を指定することにより、限定された範囲内でのみ処理を行うことができる。

# 特定の1行のみで置換を行う
sed -e '<行番号>s/パターン1/パターン2/'

# 開始行~終了行の範囲でのみ置換を行う
# sの直前に対象とする行番号を指定する
sed -e '<開始行>,<終了行>s/パターン1/パターン2/'


ある特定の行のみを置換対象とする場合、または、N行目〜M行目のみを置換対象とする場合は、
対象とする行の行番号を指定することで、処理が適用される範囲を限定することができる。

以下の例では、テキストファイルに対して、置換処理を行っている。

cat Sample.txt

111 ABC
222 ABC
333 ABC


2行目のみを処理対象とする。

sed -e '5s/ABC/OK/' Sample.txt

111 ABC
222 OK
333 ABC


2~3行目のみを処理対象とする。

sed -e '2,3s/ABC/OK/' Sample.txt

111 ABC
222 OK
333 OK


特定の行を削除する

特定の文字列を含む行を削除するには、dを指定する。

N行目またはN行目~M行目を削除する場合、削除対象となる行のパターンとdを指定することで、そのパターンを含む行を削除できる。
この処理は、置換ではなく削除であるため、置換後のパターンを指定する必要はない。

sed -e '/パターン/d'


以下の例では、テキストファイルに対して削除処理を行っている。

cat Sample.txt

111 ABC
222 ABC
333 ABC


333を含む行を削除する。

sed -e '/333/d' Sample.txt

111 ABC
222 ABC


上記は、grep -vコマンドでも同様の処理ができる。

grep -v "333" Sample.txt

111 ABC
222 ABC


空行を削除する。 空行は、行頭と行末の間に何も存在しない行であるため、正規表現の^$で表すことができる。
これを置換対象パターンに指定することで、空行を削除することができる。

cat Sample.txt

111 ABC
222 ABC


sed -e '/^$/d' Sample.txt

111 ABC
222 ABC


行中に含まれる置換パターンに関係なくN行目を削除するには、置換パターンを指定せずにdに行番号のみを指定する。

# 単一行の削除
sed -e '<行番号>d'

# 複数行の削除
sed -e '<開始行>,<終了行>d'


cat Sample.txt

111 ABC
222 ABC
333 ABC


sed -e '3d' Sample.txt
 
111 ABC
222 ABC


sed -e '2,3d' Sample.txt

111 ABC


最下行を削除するには、最下行を表す$を行番号の代わりに指定する。

cat Sample.txt

111 ABC
222 ABC
333 ABC


sed -e '$d' Sample.txt

111 ABC
222 ABC


特定の行のみを表示する

N行目またはN~M行目のみを表示するには、-nオプション、行番号、pを指定する。

# N行目を表示
sed -n '<行番号>p'

# N行目~M行目を表示
sed -n '<開始行>,<終了行>p'


1行目のみを表示する。

cat Sample.txt

111 ABC
222 ABC
333 ABC


1行目のみを表示する。

sed -n '1p' Sample.txt

111 ABC


2~3行目のみを表示する。

sed -n '2,3p' Sample.txt

111 ABC