🐸

sedコマンドによる文字列の置き換え

2022/01/18に公開

はじめに

シェルスクリプトで文字列の置換を行う場合、sedコマンドを使うことでこれを実現できます。
忘れた頃に読んで雰囲気を思い出せるようにメモとして幾つかの使用例を記載します。
※本記事ではubuntu:20.04を使用してコマンドを実行しています。試す場合はdocker run -it ubuntu:20.04 bashで可能です。

sedコマンドの使い方

sedコマンドを使った文字列置換の基本形は以下になります。
sedに続いて区切り文字と置き換えるターゲットの文字列, 置換後の文字列を指定します。
echo hogehogefugafuga | sed s'/hoge/fuga/'
上記の例だと区切り文字はスラッシュ/, 置き換えるターゲットの文字列はhoge, 置換後の文字列はfugaになります。

> echo hogehogefugafuga | sed 's/hoge/fuga/'
fugahogefugafuga

この場合、先頭のhogeのみfugaに置き換わります。
全てのhogefugaに置き換える場合は以下のように文末にgを指定することで実現できます。

> echo hogehogefugafuga | sed 's/hoge/fuga/g'
fugafugafugafuga

また、sedで指定する区切り文字はスラッシュ/以外にも;, @, _, #などの文字列を区切り文字として使用可能です。

> echo hogehoge/fugafuga/ | sed 's;hoge/;fuga/;'
hogefuga/fugafuga/

sedコマンドの応用例

1. 検索対象の再利用

&を使うことで検索対象の再利用が可能になります。

> echo hogehogefugafuga | sed 's/hoge/&&/'
hogehogehogefugafuga

上記のコマンドにおいて&hogeの文字列となり、&&hogehogeとなります。
よってhogehogehogeで置き換えることになるので、上記のような出力結果になります。

2. 後方参照

検索対象を()で囲うことで順番に番号が振られ、後方参照により、これを呼び出すことが可能です。

> echo hogehogefugafuga | sed 's/\(hoge\)\(fuga\)/\2\1/'
hogefugahogefuga

3. 正規表現の利用

sedは正規表現と組み合わせることもでき、オプションとして-Eを渡すことで拡張正規表現を使用することも可能です。(-rでも可)
拡張正規表現を使うと2の例でのエスケープ文字\は不要になります。

> echo hogehogefugafuga | sed -E 's/(h...)(f...)/\2\1/'
hogefugahogefuga

.は任意の文字列となるため、hから始まる4文字の文字列, fから始まる4文字の文字列の連結を表します。
よって3の例では次のような文字列が渡された場合も置き換えを行います。

> echo hogehaaafaaafuga | sed -E 's/(h...)(f...)/\2\1/'
hogefaaahaaafuga

2の例だと置き換える対象が見つからないため、元の文字列が出力されます。

> echo hogehaaafaaafuga | sed 's/\(hoge\)\(fuga\)/\2\1/'
hogehaaafaaafuga

4. 文字列を消す場合

置換後の文字列を指定しない場合は置き換えるターゲットの文字列が削除されます。

> echo hogehogefugafuga | sed 's/hoge//'
hogefugafuga

gを指定した場合、hogeは全て削除されます。

> echo hogehogefugafuga | sed 's/hoge//g'
fugafuga

5. 行を操作する

出力された各行に対して処理を行うこともできます。
例えばubuntuのルートディレクトリにあるディレクトリのうちliという文字列を含むものだけ出力する場合sedを使うと以下のようになります。

> ls
bin   dev  home  lib32  libx32  mnt  proc  run   srv  tmp  var
boot  etc  lib   lib64  media   opt  root  sbin  sys  usr
root@82673e1a199c:/# ls | sed -n '/li/p'
lib
lib32
lib64
libx32

liという文字列を含むパターンのみ出力を行います。
また、行番号で出力を指定することも可能です。

> ls | xargs echo
bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var
> ls | sed -n 1,6p
bin
boot
dev
etc
home
lib

-nは処理が行われた出力のみ出力するというオプションになります。sedはデフォルトでは処理が行われなかった出力はそのまま出力するため、このオプションをつけないと上記の例は動作しません。

> ls | sed '/li/p'
bin
boot
dev
etc
home
lib
lib
lib32
lib32
lib64
lib64
libx32
libx32
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var

> ls | sed 1,6p
bin
bin
boot
boot
dev
dev
etc
etc
home
home
lib
lib
lib32
lib64
libx32
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var

6. 文字列からコマンドへ整形

sedを使うことでパイプで受け取った文字列をもとにコマンドを実行することも可能です。

> echo hoge.txt | sed 's/^/touch /' | bash
root@82673e1a199c:/# ls
bin   dev  hoge.txt  lib    lib64   media  opt   root  sbin  sys  usr
boot  etc  home      lib32  libx32  mnt    proc  run   srv   tmp  var

上記の例だとecho hoge.txt | sed 's/^/touch /'の出力はtouch hoge.txtとなるため、これをbashにパイプで渡すことにより、文字列をコマンドとして実行しています。
^は文字列の頭を表しており、ここでは置き換えるターゲットには文字列を指定していないため、文字列の先頭をmv で置き換える操作が行われます。

終わりに

本記事ではsedコマンドについて、使い方を忘れてしまった際に雰囲気を思い出すため、幾つかの使用例を記載しました。
ここで示した使い方以外にもsedコマンドには様々なオプション等が用意されており、正規表現と組み合わせることでより柔軟な対応が可能になります。
自分はコマンドなどすぐ忘れるので、使い方を忘れた際にはここに戻ってきて、シュッと解決できたらと思います。

参考

Discussion