pikesaku’s blog

個人的な勉強メモです。記載内容について一切の責任は持ちません。

sedコマンドの使い方

コマンドの役割

manでは、"stream editor for filtering and transforming text"
入力データをフィルタしたり置き換えたりする。

sedコマンドで指定する項目

①オプション

スクリプト

③読み込み対象(FILE or STDIN)

動作フロー

①1行データを読み込み、「パターンスペース」と呼ばれる記憶領域に保存
②パターンスペースに保存されているデータに対して処理を行う
③パターンスペースの内容を出力してパターンスペースを空にする
④①に戻り次の行の処理を行う
 

スクリプトの指定方法について

・-e,-E,-fオプションでスクリプトを指定
・-e,-Eはスクリプト文字列を引数に取る(違いは後述)
・-fはスクリプトが記述されたファイルを引数に取る

スクリプトの構成要素

・以下要素があり
 アドレス
 コマンド
・アドレスはコマンドの実行対象を指定。以下で指定が可能
 ①行情報
 ②正規表現
・アドレスは、範囲指定も可能
 例)n行目からm行目まで
 例)n行目からm行以降まで
 例)n行目からm行目毎
 例)正規表現Aにマッチした部分から正規表現Bにマッチした部分まで
・コマンドは処理内容を指定

実行例と動作説明

-nオプション有無の違い

例1) -nオプション無の場合
# cat ./a
a
b
# sed -e '/a/p' ./a                                                                                               
a
a
b
# 

 
①1行目(a)がパターンスペースに読み込まれる
②アドレスは正規表現で指定されている(/a/)
正規表現にマッチした1行名に対してpコマンド(結果を出力)が実行され標準出力に出力される
④パターンスペースにある1行目が標準出力に出力
⑤パターンスペースは空になる
⑥2行目(b)がパターンスペースに読み込まれる
正規表現にマッチしない為、pコマンドは実行されない
⑧パターンスペースのデータを標準出力する
⑨パターンスペースは空になる

「動作フロー」で記載したように、デフォルトでパターンスペースの行を標準出力する。
そのため、1行目が2回出力されている。

例2 -nオプション有の場合

例1の④・⑧が実行されなくなる。

# cat ./a
a
b
# sed -n -e '/a/p' ./a
a
# 

 

①1行目(a)がパターンスペースに読み込まれる
②アドレスは正規表現で指定されている(/a/)
正規表現にマッチした1行名に対してpコマンド(結果を出力)が実行され標準出力に出力される
④パターンスペースは空になる
⑤2行目(b)がパターンスペースに読み込まれる
正規表現にマッチしない為、pコマンドは実行されない
⑦パターンスペースは空になる

アドレスの指定方法

例1 行番号指定
# cat ./a
a
b
c
d
# sed -n -e '1p' ./a
a
# sed -n -e '$p' ./a
d
# 

 
"$"で最終行の指定が可能

例2 行番号範囲指定
# cat ./a
a
b
c
d
# sed -n -e '1,2p' ./a
a
b
# sed -n -e '1,+1p' ./a
a
b
# sed -n -e '0~2p' ./a
b
d
# sed -n -e '1~2p' ./a
a
c
# 

 
N,Mで行番号を指定した範囲指定が可能
N,+MでN行目からM行以降の範囲指定が可能
N~MでN行目からM行間隔で出力が可能

例3 正規表現による範囲指定
# cat ./a
a
b
c
d
a
b
c
d
# sed -n -e '/a/,/c/p' ./a
a
b
c
a
b
c
# sed -n -e '/a/~2' ./a
sed: -e expression #1, char 4: 不明なコマンド: `~'
#

 
PATTERN,PATTERNで範囲指定が可能
PATTERN~Nで行間隔指定はできない

他コマンド説明

-dコマンド

アドレスで指定された行のパターンスペースの削除を行う

# cat ./a
a
b
#
# sed -e '1d' ./a
b
#

 

①1行目(a)がパターンスペースに読み込まれる
②アドレスは1行目が指定されている
③アドレスで指定された1行目のパターンスペースに対してdコマンドが実行され、パターンスペースのデータが削除される
④パターンスペースにある1行目を標準出力するが、パターンスペースが削除済みの為、何も出力されない
⑤パターンスペースは空(既に削除済み)になる
⑥2行目(b)がパターンスペースに読み込まれる
⑦アドレスで指定されていないため、dコマンドは実行されない
⑧パターンスペースのデータを標準出力する
⑨パターンスペースは空になる

-sコマンド

アドレスで指定された行のパターンスペースの置換を行う。sコマンドは、パラメータに正規表現を指定する。

# cat ./a
a a
b b
a a
# sed -e '1s/a/b/g' ./a
b b
b b
a a
#

 

①1行目(a a)がパターンスペースに読み込まれる
②アドレスは1行目が指定されている
③アドレスで指定された1行目のパターンスペースに対してsコマンドが実行され、aがbに置換される
 /a/b/gがパラメータ。aをbに置換する。
 g指定により1行内にマッチする部分が複数ある場合、全て置換される。
 g指定がない場合は、最初の部分のみ置換
④置換されたパターンスペースを標準出力する
⑤パターンスペースは空になる
⑥2行目(b b)がパターンスペースに読み込まれる
⑦アドレスで指定されていないため、sコマンドは実行されない
⑧パターンスペースのデータを標準出力する
⑨パターンスペースは空になる
⑩3行目(a a)がパターンスペースに読み込まれる
⑪アドレスで指定されていないため、sコマンドは実行されない
⑫パターンスペースのデータを標準出力する
⑬パターンスペースは空になる

他オプション説明

-i[SUFFIX]オプション

ファイルを置換するオプション。
SUFFIX指定時は、指定した文字例を付与したファイル名で入力ファイルをバックアップする。

例) SUFFIX未指定時

# echo a > ./a
# ls -i a
52977918 a
# sed -i -e '/a/p' ./a
# ls -i a
52977919 a
# cat ./a 
a
a
# 

ポイントは入力ファイルを変更せず削除し、新たに同名ファイルで生成している点。
※元ファイルのデータは維持されない。

例) SUFFIX指定時

# echo a > ./a
# ls -i ./a      
52977918 ./a
# sed -i".hoge" -e '/a/p' ./a
# ls -i ./a*
52977919 ./a  52977918 ./a.hoge
# cat ./a
a
a
# cat ./a.hoge
a
#

ポイントは既存ファイルを削除せずにa.hogeにリネームして、新たにaを生成している点。
※元ファイルのデータは維持できる。


-cオプション

"-i"と同時指定時のみ動作するオプション。-cを指定すると元ファイルをSUFFIX付きファイルとしてコピーする。
※-iのみの場合はコピーではなくリネームする

例)

# echo a > ./a
# ls -i ./a 
52977918 ./a
# sed -c -i".hoge" -e '/a/p' ./a
# ls -i ./a ./a.hoge
52977918 ./a  52977920 ./a.hoge
# cat ./a
a
a
# cat ./a.hoge
a
# 

状況に応じて使い分けるべきだが、一般的な用途では-cを付ける必要はなさそう。
どちらも、a、a.hogeのデータは同じ。aが処理後、a.hogeが処理前のデータになる。

-Eオプション

スクリプトを指定する。

"-e"は基本、"-E"は拡張
どちらも提供する機能は同じ。以下文字をメタキャラクタとして使う場合、エスケープするかしないかの違い。

+ ? { } ( ) |

 

例)

# echo 'a' | sed -n -e '/a+/p'
# echo 'a' | sed -n -e '/a\+/p'
a
# echo 'a' | sed -n -E '/a+/p'
a
# echo 'a' | sed -n -E '/a\+/p'
# 

 

ホールドスペースの説明

パターンスペース以外の記憶領域

パターンスペース・パターンスペース操作コマンド

コマンド 説明
h パターンスペースの内容をホールドスペースにコピー
H パターンスペースの内容をホールドスペースの末尾に追加
g ホールドスペースの内容をパターンスペースにコピー
G ホールドスペースの内容をパターンスペースの末尾に追加

 

実行例

ファイル内容を逆順に出力する。

# cat ./a
a
b
c
# sed -n -e 'G' -e 'h' -e '$p' ./a
c
b
a

#

 

処理の流れ

①パターンスペースに1行目の"a"が読み込まれる

パターンスペース a
ホールドスペース


②Gコマンドでホールドスペースの内容がパターンスペースの末尾に追加される。しかし、ホールドスペースは空の為、変化はなし

パターンスペース a
ホールドスペース


③hコマンドでパターンスペースの内容がホールドスペースにコピーされる

パターンスペース a
ホールドスペース a


④pコマンドは最終行のみ実行される。まだ1行目なので何も実行されない

パターンスペース a
ホールドスペース a


⑤パターンスペースに2行目の"b"が読み込まれる

パターンスペース b
ホールドスペース a


⑥Gコマンドでホールドスペースの内容がパターンスペースの末尾に追加される

パターンスペース b
a
ホールドスペース a


⑦hコマンドでパターンスペースの内容がホールドスペースにコピーされる

パターンスペース b
a
ホールドスペース b
a


⑧pコマンドは最終行のみ実行される。まだ2行目なので何も実行されない

パターンスペース b
a
ホールドスペース b
a


⑨パターンスペースに3行目(最終行)の"c"が読み込まれる

パターンスペース c
ホールドスペース b
a


⑩Gコマンドでホールドスペースの内容がパターンスペースの末尾に追加される

パターンスペース c
b
a
ホールドスペース b
a


⑪hコマンドでパターンスペースの内容がホールドスペースにコピーされる

パターンスペース c
b
a
ホールドスペース c
b
a


⑫pコマンドが最終行の為、実行される。pコマンドは現在のパターンスペースの内容を出力する

パターンスペース c
b
a
ホールドスペース c
b
a


※上記の流れで大体説明はつく。しかし、出力結果には最後に空行が入っている。
②の時に空のホールドスペースをパターンスペースに追加する時に、改行が追加されたと想定される。

# sed -n -e 'G' -e 'p' ./a|cat -A
a$
$
b$
$
c$
$
#
# sed -n -e 'g' -e 'p' ./a|cat -A
$
$
$

 

おまけ

シングルクオートをパターンマッチ指定するのが面倒
sedでのシングルクォートの置換 | hiro345
 

# echo "''" | sed -E '/\'\'/p'
> ※エスケープが効かない
# echo "''" | sed -n -E '/'\'\''/p'
'' ※エスケープし更にシングルクオートで囲えばOK。直感的でなし。
# echo "''" | sed -n -E "/''/p"
'' ※ダブルクオートで囲えばOK