sedコマンドの内部コマンドの適用範囲を指定する際には終了条件に注意!(最終行まで適用されてしまう場合)

Bash, CentOS, Cygwin, Linux, Ubuntu

はじめに

前回( sedコマンドを全行に実行させたくない場合は内部コマンドの適用範囲を指定しよう(含む、含まない、特定の行のみ、数行毎に、など) ) みた sed コマンドの範囲指定方法について、振り返ります。

  • sed の内部コマンド適用範囲は 「アドレス」 というもので設定できる
  • 「アドレス」 は 0個か1個か2個を指定できる。
  • 「アドレス」 にはパターンを表す正規表現か行番号が使える
  • 「アドレス」 の指定方法は 行アドレスパターンアドレス がある

「アドレス」 については、以下の5つの大原則がありました。

「アドレス」が指定されていなければ、コマンドは全ての行に適用される
「アドレス」が一個だけ指定されると、コマンドはその「アドレス」にマッチする全ての行に適用される

  • カンマで区切られた2個の「アドレス」が指定されると最初の「アドレス」にマッチしたから2番目の「アドレス」にマッチするまでその行も含むすべての行にコマンドが適用される
    *「アドレス」の後ろにエクスクラメーションマークをつけると「アドレス」にマッチしない全ての行にコマンドが適用される

「行アドレス」例

# 5行目を削除
$ cat any-file.txt | sed '5d'
# 5行目から10行目を削除
$ cat any-file.txt | sed '5,10d'

「パターンアドレス」例

# コメント行を削除
$ cat any-file.txt | sed '/^\s*\#/d'
# '---' から 次の '---' まで削除
$ cat any-file.txt | sed '/---/,/---/d'

カンマの後ろの条件指定に注意しないと予期しない挙動をする!

前回さらっと流してしまったが、sedコマンドのアドレス指定範囲で意外とハマってしまうケースがあります。
「範囲指定がうまく動作しない!」という方の参考になれば幸いです。

範囲指定がうまく動かないケース

テストデータを元にカンマの後ろの条件に該当しない場合にどうなるかを見ていきましょう。

cat <<'EOF' > testdata.txt
2014
2015
2017
2018
2019
EOF

上記は2014年から2019年のデータとします。ここで注意したいのは、2018年だけが抜けている点です。

2015〜2018年のデータを削除してみます。

$ sed '/2015/,/2018/d' testdata.txt
2014
2019

問題なく動作しました。

では今度は 2015〜2016年のデータを削除してみます。

$ sed '/2015/,/2016/d' testdata.txt
2014

2015年以降が全て消えてしまいました。

これは以下の挙動と同じです。

$ sed '/2015/,//d' testdata.txt
$ sed '/2015/,$d' testdata.txt

sed 範囲指定のカンマの後ろは実行中の内部コマンドの「スイッチを切る」ためのもの

以下のように挙動することを理解しておきましょう。

  • カンマの前の行アドレス指定は内部コマンドを有効にするための命令
  • カンマの後ろのアドレス指定は内部コマンドを無効にするための命令

カンマの後ろの条件に該当しない場合は全ての行に適用されてしまいます。

ひとこと

終了条件に注意!
意外と「sed が想定どおりに動いてくれない!」とハマってしまう原因になります。

Bash, CentOS, Cygwin, Linux, Ubuntu

Posted by genzouw