woshidan's loose leaf

ぼんやり勉強しています

いい加減わからない感じが強いのでsedについて少し調べてみた

sedとは

sedstream editor の略で、主にファイルかファイルの指定がなければ標準入出力を読んで何かしたら入力を修正したら標準出力へ書き込んでくれる、といった使い方が主なスクリプト言語です。

sedの記法

コマンドを一つだけ入力する場合とそうでない場合で記法が異なります。

     sed [-Ealn] command [file ...] #
     sed [-Ealn] [-e command] [-f command_file] [-i extension] [file ...]

sedのコマンドの種類

コマンドには、 http://itpro.nikkeibp.co.jp/article/COLUMN/20060227/230879/ で紹介されているものから

  • a 文字列 ... 文字列を追加する。ただし改行をしたい場合はその前に\を付ける
  • i 文字列 ... 文字列を挿入する。ただし改行をしたい場合はその前に\を付ける
  • r ファイル名 ... 指定したファイルを読み出し,追加する
  • d ... パターン・スペースを削除する
  • s/置換条件/置換文字/ ... 置換条件を置換文字に変換する。最後にgを付けた場合は置換条件に当てはまるすべての文字列が置換される
  • p ... 行を出力する

などがあります。a コマンドなどはMac OS環境下だとうまく動かないことがあるので、その場合はこちらのページを参考に gnu-sed を入れるとよいようです。

$ echo "test" | sed s/t/gu/
guest
$ echo "test" | sed p
test
test

// test.csv
// cat,dog,cow
// horse,wolf,giraffe
// anteater,bear,ape

$ sed 1d test.csv
horse,wolf,giraffe
anteater,bear,ape

今回は主に s コマンドの話をしたいので先に進みます。

アドレスとは

各コマンドについて、アドレス、コマンド1文字、コマンドパラメータなどを指定しますが、アドレスとは、処理を行う範囲の指定のことだそうです。指定方法について、 https://qiita.com/mattintosh4/items/4e4d44016be15333af11 の記事より引用させていただくと、

アドレス 範囲 行番号指定 パターン指定
0アドレス 全ての行 何も書かない 何も書かない
1アドレス 指定行 1、や 2、$ など /^1行目/ など
2アドレス 指定行〜指定行 1,3、2,$ など /^1行目/,/^3行目/ など

という風になっています。わかりづらいので、

cat,dog,cow
horse,wolf,giraffe
anteater,bear,ape

のようなCSVファイルを処理して確認してみましょう。

// 0アドレス(何も記述していない) => すべての行で処理される
$ sed s/a/A/g test.csv
cAt,dog,cow
horse,wolf,girAffe
AnteAter,beAr,Ape
// 1アドレス(数字や記号を一つだけ書く) => その行だけ処理される
$ sed 3s/a/A/g test.csv
cat,dog,cow
horse,wolf,giraffe
AnteAter,beAr,Ape
// 2アドレス(コンマ区切りで二つ指定する) => 指定した複数行が処理される
$ sed 2,3s/a/A/g test.csv
cat,dog,cow
horse,wolf,girAffe
AnteAter,beAr,Ape

sedのsコマンドでできること

眠たいのでバーッと書いちゃいます。

// 置換文字の中でマッチしたキーワードを利用する
$ echo "test" | sed s/t/gu/
guest

// s/置換条件/置換文字/ の置換文字の部分に&を置くと、マッチした単語の部分が出力される
$ echo "test" | sed 's/t/gu &/'
gu test
// 3行目の内容 anteater,bear,ape
$ sed -n '3s/a/ Changed &/gp' test.csv
 Changed ante Changed ater,be Changed ar, Changed ape

// s/置換条件/置換文字/ で置換条件に()を使ってグループ化し、置換文字の部分に\nを置くと、n番目に()のグループでマッチした部分が出力される
$ echo "test" | sed 's/\(te\)\(st\)/\2  \1/'

// s/置換条件/置換文字/ の置換条件に正規表現が使える
// 行頭 ^, 行末 $ など
$ sed -n 's/\([bcd]\)/\1_/gp' test.csv
c_at,d_og,c_ow
anteater,b_ear,ape

// -e コマンドで sコマンドをつないで、複数の条件で置換ができる
$ sed -e 's/\([bcd]\)/B/g' -e 's/\([efg]\)/E/g' test.csv
Bat,BoE,Bow
horsE,wolE,EiraEEE
antEatEr,BEar,apE

// s/置換条件/置換文字/ の後ろの部分にgをつけるとマッチした部分全体が、pをつけるとその部分を追加で出力になる
$ sed 3s/a/A/gp test.csv
cat,dog,cow
horse,wolf,giraffe
AnteAter,beAr,Ape
AnteAter,beAr,Ape

// s/置換条件/置換文字/ の後ろの部分にgをつけるとマッチした部分全体が、pをつけるとその部分を追加で出力になる
$ sed 3s/a/A/gp test.csv
cat,dog,cow
horse,wolf,giraffe
AnteAter,beAr,Ape
AnteAter,beAr,Ape

// s/置換条件/置換文字/p を -nオプション(対象の行だけ出力)と合わせると、置換処理した部分だけ出力できる
$ sed -n 3s/a/A/gp test.csv
AnteAter,beAr,Ape

他にも色々ありますが、 https://qiita.com/hirohiro77/items/7fe2f68781c41777e507 などを見ることにして慣れてきたので今日はここまでにします。

参考