文字列操作 〜SedとVimと、時々、正規表現〜


文字列操作〜SedとVimと、時々、正規表現〜


みなさんSedコマンド使ってますか?
手打ちで文字列編集とかしてません?
正規表現使ってますか?
Vimはエディターの好みの問題なので興味あれば使ってみてください。

今回はSedコマンドと正規表現、Vimでの文字列置換やあれこれを書きます。

Sedコマンドて何者ですか?

Sedコマンド - wikipediaより一部引用
  • sed(セド)は、入力ストリーム(ファイルまたはパイプラインからの入力)に対してテキスト変換などのデータ処理をおこなうために使用されるプログラムである。名称「sed」は「ストリームエディタ」を意味する英語「stream editor」に由来する。
  • sedは、入力を行単位で読み取り、sedスクリプトと呼ばれるシンプルな命令文に従ってテキスト変換などの編集をおこない、また行単位で出力する。基本的には照合ルールに従い場合分けをおこなうフィルタと捉えることができる。オリジナル版のsedはベル研究所のマクマホンによって1973年前後に開発されたUNIXユーティリティで、現在ではコマンドラインをサポートするさまざまなオペレーティングシステムに搭載されている。
  • 大量のテキストファイルに対して一括で定形の処理をおこなう場合に大きな威力を発揮する。正規表現に対応しており、ある条件の範囲内の文字列を探し出して処理することができる。特定の条件に合った文字列を検索し置換するなどの用途に用いる。

テキスト変換などのデータ処理をおこなうために使用されるプログラム

つまりは文字列操作が行えます。
そしてこれ!これが一番強い!そしてVimとの組み合わせもなかなか強い!
※強い=便利

大量のテキストファイルに対して一括で定形の処理をおこなう場合に大きな威力を発揮する。
正規表現に対応しており、ある条件の範囲内の文字列を探し出して処理することができる。
特定の条件に合った文字列を検索し置換するなどの用途に用いる。

実際に使ってみます。

$ cat test.txt
010
035

↑のようなテキストデータがあるとします。
試しに「0 (ゼロ)」を「A」に置換してみましょう!

$ cat test.txt | sed "s/0/A/g"
A1A
A35

できました。最初の文字列「010」が「A1A」になってますね。
なぜなら全ての「0」を「A」へ置換したから。

では次に「先頭の『0』のみを『A』へ」置換してみましょう。

$ cat test.txt | sed "s/^0/A/g"
A10
A35

できました。先ほどとは若干コマンドが異なります。
sedコマンドでは正規表現を利用する際、オプションに「-e」ではなく「-E」を利用します。
また、「先頭」という条件であるため、「0 (ゼロ)」の前に「^」を記述しています。

※追記(2018/09/05)

勘違いしてました。オプション無しでもデフォルトの動作として、正規表現をサポートしております。
-e-Eのオプションについて、正しい動作は以下の通りです。

オプション 動作
-e スクリプト(コマンド)を追加する
-E 正規表現を拡張正規表現として解釈する

コメントにてご指摘いただきありがとうございます。

では次に、「先頭の『0』を『A』へ、末尾の『0』を『Z』へ」置換してみましょう。

$ cat test.txt | sed "s/^0/A/g" | sed "s/0$/Z/g"
## もしくは
$ cat test.txt | sed -e "s/^0/A/g" -e "s/0$/Z/g"
A1Z
A35

こんな感じ。正規表現便利。

正規表現の実力はこんなもんじゃない

  • 正規表現についてはこちらがわかりやすいです

「『A〜Z』で始まり、何文字か続いた場合『ああああ』に置換」

$ cat test.txt
ABCD_1234_ABCD

$ cat test.txt | sed "s/^[A-Z]*/ああああ/g"
ああああ_1234_ABCD

ですとか。使い方は色々。

Vimの小技

エディターとして利用されるVimですが、コマンドによる置換や文字列の操作が可能なのです。
試しにコメントの行を消してみましょう。(.sh ファイルじゃなくても良いです)

$ cat test.sh 
# test
# aaaaaaa
コマンド書いたよ
# lkfdbjfgjbas:
# hoge

このような適当なファイルを用意します。
Vimでファイルを開き、コメント行を意味する「#」を検索、その後マッチした行を削除します。おまけで逆のパターンも。

$ vi test.sh

# 編集モードに入っていない状態で
/#

# 「#」を含む行を削除する場合
:g//d

$ cat test.sh 
コマンド書いたよ

# 「#」を含まない行を削除する場合
:v//d

$ cat test.sh 
# test
# aaaaaaa
# lkfdbjfgjbas:
# hoge

置換もできます。

vi test.sh

# 編集モードに入っていない状態で
:%s/#/@/g

$ cat test.sh 
@ test
@ aaaaaaa
コマンド書いたよ
@ lkfdbjfgjbas:
@ hoge

「#」を「@」へ変換できました。この置換機能では、正規表現も利用できます。

$ cat test.txt
Android_1234
Android_4321
iOS_1234
iOS_4211
1234_Android
1234_iOS

# vimで開いて
vi test.txt

# 検索
/_[0-9]*$

# 置換
:%s///g

$ cat test.txt
Android
Android
iOS
iOS
1234_Android
1234_iOS

パッとみてなぜこうなったか理解できたなら、直感で初歩的な正規表現が利用できるようになっているかと思います。

最後に

「別にコマンド使わずにエディタでよくね?」と思われた方へ。

(……きこえますか…今… あなたの…脳中に…直接… 呼びかけています……サイズの大きいファイルだったり……Vim以外のエディタがない環境だった場合…………
インフラをやっていると……大量の……ログを……見る必要が……あるのですよ……)

そんな来るか来ないかもわからない時のためにsedコマンド、Vim、そして正規表現を知っておきたい。
まぁ、Vimでログファイル開いたら死ぬんだけど。。。catとか色々やりようはありますよね!
これらを組み合わせて利用することで作業効率がグッと上がったりすると、僕は思ってます。

少なくともsedと正規表現は覚えていた方が得だと思います。