Memoize

BasicWerk   EC Support   Technique   Facebook  

20140608153158_sed

sed

 

Basic

  1. sed は非破壊的である。
  2. よって、sed でフィルターしたテキストを保存したい場合はリダイレクト処理が必要。
  3. sed はスクリプトの先頭にアドレスやパターンを指定しない限り、入力に対してグローバルに作用する。

 

 

gフラグ

# これは各行の最初の old を new に置き換える
% sed 's/old/new/' file
 
# これは各行の全ての old を new に置き換える
% sed 's/old/new/g' file

 

 

-e オプションと ;

コマンドライン上で簡単なスクリプトを複数並べるとき、

# -e オプションを使って並べる
% sed -e 's/old/new/' -e 's/^new/new2/' file
 
# 若しくは sed のコマンドセパレータ ; で並べる
% sed 's/old/new/; s/^new/new2/' file

 

 

-f スクリプトファイル

複雑な処理はスクリプトファイルに纏めておき、-f オプションで呼び出すのが適切。

 

こんな HTML があったとしよう。

sample.html
<ol>
<li>aaa</li>
<li>bbb</li>
<li>ccc</li>
</ol> 
 
<ol>
<li>iii</li>
<li>jjj</li>
<li>kkk</li>
</ol>
 
<ul class="summary">
</ul>

 

バラバラに書かれた項目リストを末尾の ul にサマるには、

sample_sctipt.sed
# <ol>, </ol> を削除(d)
# <li>...</li> をキャプチャ(H 先頭に改行を挿入)
# キャプチャした <li>...</li> を削除(d)
# <ul class="summary"> の後にキャプチャしたリストをペースト(G)
 
/<ol>/d
/<\/ol>/d
/<li>.*<\/li>/{
    H
    d
}
/<ul class="summary">/G

などとスクリプトを作っておいて、

% sed -f sample_sctipt.sed sample.html

と呼び出すと、

 
<ul class="summary">
 
<li>aaa</li>
<li>bbb</li>
<li>ccc</li>
<li>iii</li>
<li>jjj</li>
<li>kkk</li>
</ul>
 

 

 

-n オプション

スクリプトで明示的に p (print) フラグを指定した行のみ出力したいときは -n フラグを付ける。

例えば先程の sample.html で <ol> から始まって </ol> で終わる部分のみを出力したいなら、

% sed -n '/<ol>/,/<\/ol>/p' sample.html
<ol>
<li>aaa</li>
<li>bbb</li>
<li>ccc</li>
</ol> 
<ol>
<li>iii</li>
<li>jjj</li>
<li>kkk</li>
</ol>

 

 

アドレス

  1. アドレスは2つまで指定できる。アドレスはカンマで区切る。
  2. アドレスは行番号、若しくは正規表現で指定する。
  3. アドレスを1つ指定すると、そのアドレスにマッチする行にだけコマンドが適用される。
  4. アドレスを2つ指定すると、1つ目のアドレスにマッチしてから2つ目のアドレスにマッチするまで(その行も含めて)コマンドが適用される。
  5. アドレスに続けて ! を付けるとその行は無視される。

 

# 空行を削除する
% sed '/^$/d' file
 
# 50行目以降を削除する
% sed '50,$d' file
 
# 1行目から最初に見つかった空行までを出力する
% sed -n '1,/^$/p' file
 
# <ul>...</ul> 以外の部分を削除する
% sed '/<ul>/,/<\/ul>/!d' file

 

アドレスの範囲に複数のコマンドを適用する場合は {...} で囲む。

sample_script2.sed
# <ol>...</ol> の範囲内にある
# ol 自身と li を大文字にする
/<ol>/,/<\/ol>/{
    s/ol/OL/g
    s/li/LI/g
}

 

 

 

Sed Tips

 

以降使うサンプルを改めよう。

 

sample.html
<p>Jun</p>
<ol>
<li>client aaa--mtg--6/10</li>
<li>client bbb--mtg--6/13</li>
<li>client ccc--project XXX--LIMIT! 6/20 launch</li>
</ol> 
 
<p>Jul</p>
<ol>
<li>client aaa--project YYY--7/10 test</li>
<li>client ddd--mtg--7/20</li>
</ol>
 
<div class="summary">
</div>

 

 

番号で指定してマッチさせる

sample.html のリストに含まれる2個目の -- だけをカンマに置換

% sed 's/--/,/2' sample.html
 
...
<li>client aaa--mtg,6/10</li>
<li>client bbb--mtg,6/13</li>
<li>client ccc--project XXX,LIMIT! 6/20 launch</li>
...
 

 

 

行中の特定の文字だけ切り出す

マッチした行の中から更に \(...\) で切り出す。

sample.html のリストに含まれる文字だけを切り出し、-- をカンマに置換して CSV にしてみよう。

txt_to_csv.sed
# リスト行以外を削除
/^<li>/!d
 
# 文字列を切り出して、
s/<li>\(.*\)<\/li>/\1/g
 
# -- をカンマに置換
s/--/,/g

 

% sed -f txt_to_csv.sed sample.html > task.csv
 
client aaa,mtg,6/10
client bbb,mtg,6/13
client ccc,project XXX,LIMIT! 6/20 launch
client aaa,project YYY,7/10 test
client ddd,mtg,7/20

 

! が含まれてるリスト内の文字列を強調する。

% sed '/!/s/\(<li>\)\(.*\)\(<\/li>\)/\1<strong>\2<\/strong>\3/g' sample.html
 
...
<ol>
<li>client aaa--mtg--6/10</li>
<li>client bbb--mtg--6/13</li>
<li><strong>client ccc--project XXX--LIMIT! 6/20 launch</strong></li>
</ol> 
...

 

 

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

  1. パターンスペースは入力を保持するバッファ
  2. ホールドスペースは出力を保持するバッファ

 

push h ホールドスペースを上書き
push H ホールドスペースに追加
pop g パターンスペースを上書き
pop G パターンスペースに追加
swap x ホールドスペースとパターンスペースを入れ替え

 

例を見てみよう。

 

リスト部分(<li>...</li>)を収集してサマリーを作る。

summary.sed
# H でリストの収集
/<li>/H
/class="summary"/{
    # 次の行に移動
    n
 
    # ホールドスペースとパターンスペースを Swap
    # H で収集したリストがパターンスペースに。	
    # 現在行(<div class="summary">)がホールドスペースに。	
    x
 
    # ホールドスペース(<div class="summary">)に
    # 改行とパターンスペース(収集したリスト)を追加
    G
 
    # ホールドスペースを編集->出力
    s/li>/p>/g
}

実行してみる。

% sed -f summary.sed sample.html
 
...
<p>Jul</p>
<ol>
<li>client aaa--project YYY--7/10 test</li>
<li>client ddd--mtg--7/20</li>
</ol>
 
<div class="summary">
 
<p>client aaa--mtg--6/10</p>
<p>client bbb--mtg--6/13</p>
<p>client ccc--project XXX--LIMIT! 6/20 launch</p>
<p>client aaa--project YYY--7/10 test</p>
<p>client ddd--mtg--7/20</p>
</div>
 

 

 

r でファイルの読み込み

既に存在しているファイルを読み込むには r を使う。

r はパターンがマッチした次の行に読み込みファイルの内容を追加する。

% sed '/class="summary"/r summary.html' sample.html 

 

 

sed の終了 q

q は1つのパターンだけを受け取って sed の処理を終了する。

# これは実質 head -n 10 file と同じ
% sed 10q file
 
# 何かのパターンにマッチするまで出力
% sed '/^$/q' file

 


© Shin Nakamura/BasicWerk 2014