どこでも見れるメモ帳

とあるSEの備忘録。何かあれば気軽にコメントください〜

sedによる文字列操作

f:id:ni66ling:20160611160134p:plain

はじめに

sed*1便利ですよね.ちょっとした文字列操作が簡単にできます.
ただ,日常的に使わないと,コマンドとかオプションとかを覚えるのが難しいですよね.
ワンライナーな用途を前提として,どういった使い方ができるのか,整理してみました.

sedコマンドの構造

sedコマンドは,おおまかに次の3つの構造からなります.

  • A. コマンドオプション(入力ファイルを編集する?標準出力を抑制する?など)
  • B. 範囲指定(どの行について処理する?)
  • C. 文字列操作(どういう文字列操作をする?)

例えば,

$ sed -i '3,10 s/hoge/fuga/g' input.txt

であれば,

  • A. コマンドオプション:「-i」:B.C.の操作結果を入力ファイル(input.txt)に上書きする
  • B. 範囲指定:「3,10」:3〜10行目について
  • C. 文字列操作:「s/hoge/fuga/g」:hogeがあれば全てfugaに置換する

という処理となります.この例から分かるように,

$ sed [コマンドオプション] '[範囲指定] [文字列操作]' [入力ファイル]

となります.ここでは,[入力ファイル]をとっていますが,パイプからも入力として渡せます.

$ cat [入力ファイル] | sed [コマンドオプション] '[範囲指定] [文字列操作]'

では,[コマンドオプション],[範囲指定],[文字列操作]について詳しく見ていきます.

A. 代表的な[コマンドオプション]について

a. スクリプトを直接記述「-e」

$ sed -e '[範囲指定] [文字列操作]' [入力ファイル]
# 例
$ sed -e '3,10 s/hoge/fuga/g' input.txt #結果が標準出力に出力される


b. 入力ファイルを編集「-i」

$ sed -i '[範囲指定] [文字列操作]' [入力ファイル]
# 例
$ sed -i '3,10 s/hoge/fuga/g' input.txt #結果が入力ファイル(input.txt)に上書きされる


c. 標準出力を抑制「-n」

$ sed -n '[範囲指定] [文字列操作]' [入力ファイル]
# 例
$ sed -i '3,10 s/hoge/fuga/g p' input.txt #明示的に「p」した行のみ出力される


B. 代表的な[範囲指定]について

a. 行数範囲指定(◯行目〜△行目について文字列操作「◯,△」)

$ sed [コマンドオプション] '[開始行数],[終了行数] [文字列操作]' [入力ファイル]
# 例
$ sed -e '3,10 s/hoge/fuga/g' input.txt  #3〜10行目
$ sed -e '3,10! s/hoge/fuga/g' input.txt #3〜10行目以外.!をつけると否定


b. 行数範囲指定(◯行目〜◯+△行目について文字列操作「◯,+△」)

$ sed [コマンドオプション] '[開始行数],+[行数] [文字列操作]' [入力ファイル]
# 例
$ sed -e '3,+7 s/hoge/fuga/g' input.txt  #3〜10(=3+7)行目
$ sed -e '3,+7! s/hoge/fuga/g' input.txt #3〜10(=3+7)行目以外.!をつけると否定


c. 正規表現マッチ行指定(正規表現マッチした行について文字列操作「/regex/」)

$ sed [コマンドオプション] '/[正規表現]/ [文字列操作]' [入力ファイル]
# 例
$ sed -e '/p.*o/ s/hoge/fuga/g' input.txt  #正規表現/p.*o/にマッチした行
$ sed -e '/p.*o/! s/hoge/fuga/g' input.txt #正規表現/p.*o/にマッチした行以外.!をつけると否定


d. 正規表現マッチ行範囲指定(正規表現マッチした◯行目〜正規表現マッチした◯行目について文字列操作「/regex/,/regex/」)

$ sed [コマンドオプション] '/[開始の正規表現]/,/[終了の正規表現]/ [文字列操作]' [入力ファイル]
# 例
$ sed -e '/p.*o/,/h.*a/ s/hoge/fuga/g' input.txt  #正規表現/p.*o/〜正規表現/h.*a/にマッチした行
$ sed -e '/p.*o/,/h.*a/! s/hoge/fuga/g' input.txt #正規表現/p.*o/〜正規表現/h.*a/にマッチした行以外.!をつけると否定


e. 行飛ばし指定「n」

$ sed [コマンドオプション] '[範囲指定]n [文字列操作]' [入力ファイル]
# 例
$ sed -e '3n s/hoge/fuga/g' input.txt          #3行目飛ばし
$ sed -e 'n s/hoge/fuga/g' input.txt           #全ての行について1行飛ばし
$ sed -e '{n;n;n} s/hoge/fuga/g' input.txt     #全ての行について3行飛ばし.{}で括るとグルーピングして一括実行
$ sed -e '3,20{n;n;n} s/hoge/guga/g' input.txt #3〜20行目について3行飛ばし.{}で括るとグルーピングして一括実行


f. 未指定「」

$ sed [コマンドオプション] '[文字列操作]' [入力ファイル]
# 例
$ sed -e 's/hoge/fuga/g' input.txt #未指定=全ての行


C. 代表的な[文字列操作]について

a. 文字列の全置換(◯を△に全置換「s/◯/△/g」)

$ sed [コマンドオプション] '[範囲指定] s/[置換対象文字列]/[置換後文字列]/g' [入力ファイル]
# 例
$ sed -e 's/hoge/fuga/g' input.txt             #マッチしたhogeをすべてfugaに置換
$ sed -e 's/\(hoge\)\(fuga\)/\2\1/g' input.txt #hogeとfugaを順序入れ替え.[置換対象文字列]で\(\)で括ると,
                                               #[置換後文字列]にて左から「\1」,「\2」,..で参照できる
$ sed -e 's/hoge/&&/g' input.txt               #hogeをhogehogeに置換.[置換後文字列]にて「&」でマッチした内容を
                                               #参照できる


b. 文字列の指定置換(◯番目にマッチした△を❏に置換「s/△/❏/◯」)

$ sed [コマンドオプション] '[範囲指定] s/[置換対象文字列]/[置換後文字列]/[置換対象]' [入力ファイル]
# 例
$ sed -e 's/hoge/fuga/3' input.txt #3番目にマッチしたhogeをfugaに置換


c. 行削除「d」

$ sed [コマンドオプション] '[範囲指定] d'
# 例
$ sed -e '/hoge/ d' #hogeが含まれる行を削除


d. 出力「p」

$ sed [コマンドオプション] '[範囲指定] p'
# 例
$ sed -ne '/hoge/ p' #hogeが含まれる行だけを標準出力


より高度な操作

a. 複数の文字列操作(コマンド1とコマンド2の同時実行:「コマンド1;コマンド2」)

$ sed [コマンドオプション] '[範囲指定1] [文字列操作1];[範囲指定2] [文字列操作2]]'
# 例
$ sed -e '/hoge/d; /foo/d; s/fuga/piyo/g' #hogeとfooが含まれる行を削除.fugaをpiyoに全置換


b. ネスト化した文字列操作(範囲指定◯に対して文字列操作△と文字列操作❏「◯{△;❏}」)

# {}内のコマンドを,その左に対して実行する
# 例
$ sed -e '/hoge/,/fuga/{/piyo/d;/hogera/d}' #正規表現/hoge/〜正規表現/fuga/にマッチした行について,
                                            #正規表現/piyo/と正規表現/hogera/にマッチした行を削除

おわりに

いかがでしたでしょうか?
sedは使えるようになると強力な武器になると思います.
しかし,使うことを敬遠してしまうと,すぐにオプションを忘れてしまいがちですよね…
日常的に使って,どんどん使えることを増やせるように心がけたいと思います^^

*1:Stream EDitor