💭

sedの使い方

2021/01/31に公開
1

sedコマンドについて確認した。

sedは「Stream EDitor」のことで、Streamはfileやpipe, stdinをさす。

実行環境はmac OSである。mac OSのsedはBSD系のコマンドである。

man sedで確認してみる。

The sed utility reads the specified files, or the standard input if no files are specified, modifying the input as specified by a list of commands. The input is then written to the standard output.

「指定されたファイルか標準入力を受けつけ、入力を変更する」というコマンドである。

sedとawkの使い分け

awkはaction部分でプログラミングができる。そのため条件分岐などの制御構文が利用可能であり、高機能である。

簡易なテキスト変換はsedで行い、それ以上の複雑な処理がある場合はawkを使うといい。

基本的な使い方

sed1.txtというファイルを用意する。
xf

hello hello
hello2 hello2

基本的な使い方は以下である。

sed -e s/置換前の文字列/置換後の文字列/ ファイル名

例えば、helloworldに変換するのは以下。

sed s/hello/world/ sed1.txt

出力

world hello
world2 hello2

この出力は、sed1.txtを書き換える訳ではなく、標準出力として表示されるだけである。

sedはdefaultでは全ての行を出力する。

また、出力上では、各行で最初に出現するhelloのみ変更されている。

s/置換前の文字列/置換後の文字列/における/はdelimiterと呼ばれる。

このdelimiterは/以外に:_|,も使うことができる。

sed 's_hello_world_' sed1.txt
sed 's:hello:world:g' sed1.txt
sed 's|hello|world|g' sed1.txt
sed 's,hello,world,' sed1.txt

出力

world world
world2 world2

異なるdelimiterを使うと可読性が上がる。(https://en.wikipedia.org/wiki/Leaning_toothpick_syndrome#Sed)

またパターンマッチ部分は複数定義できる。

echo 'hello world' | sed 's/hello/Hello/; s/world/World/'
// Hello World

行内でパターンマッチした全てのテキストを変更する

パターンマッチ時に/gと指定することで、global replacementを行うことができる。

sed s/hello/world/g sed1.txt
world world
world2 world2

変更した行だけ表示する

オプションなしだと、パターンマッチが発生してない行も標準出力に含まれる。

sed s/2/world/ sed1.txt

出力

hello hello
helloworld hello2

-npを使うことで、変更された行のみを表示できる。

sed -n s/2/world/p sed1.txt
helloworld hello2

k番目に出現した文字だけ変更する

/k(kは出現番号)とすることで、実現できる

echo hoge hoge hoge hoge | sed s/hoge/fuga/2  
// hoge fuga hoge hoge

行番号を指定して変更する

2~4行目で、文字列変換をする。

echo "hello\nhello\nhello\nhello" | sed '2,4s/hello/world/'
/*
hello
world
world
hello
*/

2行目から最終行まで変換。

echo "hello\nhello\nhello\nhello" | sed '2,$s/hello/world/'

行番号を指定して削除

echo "hello1\nhello2\nhello3\nhello4" | sed 2d    
/*
hello1
hello3
hello4
*/
echo "hello1\nhello2\nhello3\nhello4" | sed 2,4d
// hello1

パターンマッチをして含む行を削除

echo "hello1\nhello2\nhello3\nhello4\nhello5" | sed '/hello2/,/hello4/d' 
/*
hello1
hello5
*/

出力を別ファイルに書き出す

/w <ファイル名>とすることで、変換後の内容を指定するファイル名に書き出すことができる。

sed 's/hello/world/w sed1_output.txt' sed1.txt

パターンマッチした文字列を複製させる

パターンマッチした文字列は&に格納できる。これを複数並べることで、パターンマッチした文字列を複数回数表示することができる。

echo "123 abc" | sed 's/[0-9]*/& &/'  
// 123 123 abc
echo "123 abc" | sed 's/[a-z].*/& &/'
//123 abc abc

行数を表示

echo "hello1\nhello2\nhello3\nhello4\nhello5" | sed '=' 
1
hello1
2
hello2
3
hello3
4
hello4
5
hello5

ある文字列を含む行のみで、文字列置換

fugaを含む行で、aをbに置換。

echo "1hogeaaa\n2fugaaaa" | sed '/fuga/s/a/b/g'
/*
1hogeaaa
2fugbbbb
*/

シングルクォートで囲んでもいい

正規表現のパターンマッチの部分はクォートで囲んでもいい。

sed 's/hello/world/g' sed1.txt

はクォートがない場合と同じ挙動である。

エスケープ

()で囲まれた文字をパターンマッチし、変換したい。

echo "(123) (aa)" | sed -E 's/([1-9]+)/hoge/' 
// (hoge) (aa)

この場合 バックスラッシュ\を利用することで実現できる。

echo "(123) (aa)" | sed -E 's/\([1-9]+\)/hoge/'
// hoge (aa)

extended regular expression

BSD系のsedではオプション-Eをつけることで、basic regular expressionからextended regular expressionへ切り替えることができる。

+?が使用可能になる。

echo "123 abc" | sed -E 's/[a-z]+/& &/'
//123 abc abc

Back Reference

「後方参照」と呼ばれるもので、以下のようなもの。

これは、 条件内で「(」「)」で後方参照したい箇所を囲むことで、囲った個所を前から順に「\1」「\2」で参照するもの。

echo 'abcdef' | sed -e 's/\(...\)\(...\)/\2\1/g'
// defabc

https://www.gnu.org/software/sed/manual/html_node/Back_002dreferences-and-Subexpressions.html

echo "James Bond" | sed -E 's/(.*) (.*)/The name is \2, \1 \2./'
// The name is Bond, James Bond.

BSD版のsedでは大文字、小文字の変換ができない。

GNU版のsed: https://www.gnu.org/software/sed/manual/sed.html

Finally, as a GNU sed extension, you can include a special sequence made of a backslash and one of the letters L, l, U, u, or E. The meaning is as follows:(略)

\L等を使い、アルファベットの大文字小文字の変換が可能。

BSD版のsed: https://www.freebsd.org/cgi/man.cgi?query=sed&sektion=&n=1

できない。

echo "(a)\n(b)\n(c)" | sed 's/^\(.\)\(.\)\(.\)/\3\2\1/'
/*
)a(
)b(
)c(
*/
echo "asdf@gmail.com" | sed 's!@[a-z].*!!'
// asdf

mac OSにはなぜBSD系コマンドが採用されているか

  • Mac OSの前身となるOSは、NeXTで開発され、それはBSD系のOSであるMach OS(マークOS、マイクロカーネル方式)を改良して作られた。
  • AppleはNeXTのユーザーインターフェイスをMacintoshユーザーフェイスに置き換えた。
  • Appleは徐々にNeXTのモジュールを減らし、BSDの素のモジュールとAppleで開発したモジュールで置き換えるようにしている。
  • Mach OSのマイクロカーネルも、AppleのXNU hybrid kernelで置き換えられた。macOS Catalina 10.15にはNeXTのモジュールは残っておらず、BSDのソフトウェアコンポーネントと、Appleの独自のコンポーネントから成る。

なお、

参考

GNUのsed

https://linuxconfig.org/learning-linux-commands-sed

参考

正規表現可視化

Discussion

mpywmpyw

BSD sed と GNU sed には多数の非互換がありますが, 個人的に一番つらいと感じるのは -i オプションの非互換ですね…(調べてみてください)

この点があるので, in-place で置換したいときは Perl 1 択かなぁとなっております…