sコマンドは、正規表現を用いて現在のパターンスペースのマッチ部分を置換する。
sコマンドの書式は、s/正規表現/置換文字列/フラグ
。ここで「置換文字列」とはマッチした文字列をこれで置換するということ。
フラグは置換の動作を変更するもので、0個以上指定できる。
アドレス部分でも正規表現を用いれば、いったん絞り込んでからのラクな正規表現を使える。また、置換文字列の中でマッチ部分を参照する&
記号やマッチしたグループを番号で参照する\1
(1番目のグループ)、\2
…を使える。
sed
コマンドのデフォルトは基本正規表現なので、拡張正規表現(+
などの表現)を有効にしたいなら--regexp-extended
オプションを付けること。
input='1行目 りんごジュース
2行目 みかんジュース
3行目 いちごケーキ'
echo "$input" | sed 's/ジュース/アイス/'
アドレスなしだと全入力行が対象になるので、出力はこうなる。
1行目 りんごアイス 2行目 みかんアイス 3行目 いちごケーキ
input='1行目 りんごジュース
2行目 みかんジュース
3行目 いちごケーキ'
echo "$input" | sed '/1行目/ s/ジュース/アイス/'
アドレス1個なら、アドレスにマッチした入力行が対象になるので、出力はこうなる。
1行目 りんごアイス 2行目 みかんジュース 3行目 いちごケーキ
input='1行目 りんごジュース
2行目 みかんジュース
3行目 いちごジュース'
echo "$input" | sed '/1行目/,/2行目/ s/ジュース/アイス/'
アドレス2個なら、アドレス1からアドレス2までの入力行が対象になるので、出力はこうなる。
1行目 りんごアイス 2行目 みかんアイス 3行目 いちごジュース
例えば「数字にマッチした部分を()で囲みたいが、マッチする可能性のある数は無限にある」ようなケースなら、「実際にマッチしたもの」を利用(参照)して変換する必要がある。
そこで、置換文字列の中で、マッチ部分を参照する&
記号やマッチしたグループを番号で参照する\1
(1番目のグループ)、\2
…を使える。
input='1行目 りんごジュース
2行目 みかんジュース
3行目 いちごケーキ'
# 拡張正規表現
echo "$input" | sed --regexp-extended 's/[1-9]+行目/(&)/'
上記は、マーカーの&
がマッチした文字列を表現しており、マッチ部分を()で囲む処理をしている。出力はこうなる。
(1行目) りんごジュース (2行目) みかんジュース (3行目) いちごケーキ
正規表現でグループ表現を用いた場合、マッチしたグループを置換文字列の中で番号順に\1
(1番目のグループ)、\2
…というように参照できる。
input='1行目 りんごジュース
2行目 みかんジュース
3行目 いちごケーキ'
# 拡張正規表現
echo "$input" | sed --regexp-extended 's/([1-9]+行目) (.+ジュース)/(\1) [\2]/'
上記はマッチしたグループ1を()で、グループ2を[]で囲む処理をしているので、出力はこうなる。
(1行目) [りんごジュース] (2行目) [みかんジュース] 3行目 いちごケーキ
sコマンドの置換の動作を変更するフラグを0個以上指定できる。フラグが複数ならgi
のように続ける。
フラグ | 意味 |
---|---|
g | 複数マッチしたら全て置換。デフォルトでは一つ目のマッチだけ置換となる。 |
番号 | 複数マッチのうち、この順番でマッチしたものだけ置換。 |
p | 置換が行われた場合、現在のパターンスペースを出力。スクリプト末尾の段階の出力は別途行われる。 |
w ファイル名 | 置換が行われたパターンスペースだけをファイルに出力。置換が全くなかった場合、既存ファイルは空ファイルになってしまう。スクリプト末尾の段階の出力は別途行われる。 |
e | 置換が行われた場合、置換したパターンスペースをBashコマンドとして実行し、その出力でパターンスペースを置き換える。 |
i | 大文字小文字を同一視。 |
複数マッチしたら全て置換。
# デフォルトでは一つ目のマッチだけ置換
echo 'abc abc' | sed 's/abc/ABC/'
ABC abc
# gフラグでマッチ全て置換
echo 'abc abc' | sed 's/abc/ABC/g'
ABC ABC
複数マッチのうち、この順番でマッチしたものだけ置換。
# 2番目だけ置換
echo 'abc abc abc' | sed 's/abc/ABC/2'
abc ABC abc
置換が行われた場合、現在のパターンスペースを出力。
input='1行目 りんごジュース
2行目 みかんジュース
3行目 いちごケーキ'
echo "$input" | sed 's/いちご/ショート/p'
上記のpフラグにより、置換が行われた場合の出力が別途あるので、出力はこうなる。
1行目 りんごジュース 2行目 みかんジュース 3行目 ショートケーキ 3行目 ショートケーキ
置換が行われたパターンスペースだけをファイルに出力。
input='1行目 りんごジュース
2行目 みかんジュース
3行目 いちごケーキ'
# ファイルnewPatternに上書きなので注意
echo "$input" | sed 's/いちご/ショート/w newPattern'
上記は置換が行われた場合、その新しいパターンスペースだけがファイルnewPatternに上書きされる。つまりnewPatternのファイル内容は、
3行目 ショートケーキ
ここでもし置換が全く行われなかったら、ファイルnewPatternは空ファイルになってしまうので注意。
これとは別に標準出力は下記のように行われる。
1行目 りんごジュース 2行目 みかんジュース 3行目 ショートケーキ
置換が行われた場合、置換したパターンスペースをBashコマンドとして実行し、その出力でパターンスペースを置き換える。
echo 'echo "Hello world!"' | sed 's/world/sed/e'
上記はパターンスペースの「echo "Hello world!"」という文字列を「echo "Hello sed!"」に変換し、それをBashコマンドとして実行し、その出力をパターンスペースに上書きしているので、出力はこうなる。このフラグ需要あるの?
Hello sed!
大文字小文字を同一視。
echo 'abc ABC AbC aBC' | sed 's/abc/xyz/gi'
上記は元の正規表現は「abc」と小文字だが、iフラグで大文字・小文字を無視(同一視)しているので、出力はこうなる。(gフラグでマッチ全て置換)
xyz xyz xyz xyz