【Linux入門】sedコマンドの基本を学ぶ

ファイル処理の際に大量のデータを加工したり・抜き出したりする場面は多いと思います。そこでよく使われるのがsedコマンドです。sedコマンドは充実した置換機能が魅力ですが、書式がやや特殊(?)なので初心者には少しとっつきにくいコマンドでもあります。

本稿ではsedコマンドの使い方を丁寧に解説します。


目次

sedコマンドの用法
sedコマンドで指定した行を表示する
 ・「最終行から上にn番目の行」?
sedコマンドで文字列を消去
sedコマンドで文字列を置換
 ・「’」と「”」の使い分け
 ・置換したい文字列が「/」を含むとき
 ・「&」や「\」で置換したいとき
sedコマンドで文字列(行)を追加・挿入
 ・該当行or指定行の先頭or末尾に文字列を追加する
 ・特定の文字列を含む行を丸ごと置換したいとき
Tips1:空行を削除する
Tips2:複数の置換を同時に行う


 sedコマンドの用法

sedコマンドの基本的な使い方は以下のようになります。

 

$ sed オプション (スクリプト) ファイル名

 

(※「$ 」はコマンド受付中のマークです。既に表示されているので皆さんが入力する必要はありません(環境によっては「# 」になっているかもしれません))

スクリプトとは「アドレスとコマンドを並べて書いたもの」のことであり、行番号または正規表現を指しています。要するにどの行に対してどのような操作をするのか、ということを指定するのがスクリプトです。この辺りは習うより慣れた方が良いと思いますので、具体的な使い方を見ていきましょう。

 

 sedコマンドで指定した行を表示する

それでは「kawa.txt」というデータセットを用いて使用法を見ていきましょう!

実際にコマンドを試してみたい方のために流路延長Top10の河川名と延長、流域面積のリストを作りましたので、必要に応じてご活用下さい。

» 流路延長Top10河川のリスト

sinano   367km 11900km2
tone     322km 16840km2
ishikari 268km 14330km2
tadami   260km  2260km2
teshio   256km  5590km2
kitakami 249km 10150km2
abukuma  239km  5390km2
kiso     229km  9100km2
mogami   229km  7040km2
tenryu   212km  5050km2

» 閉じる

sedコマンドを使えば「5行目を表示する」のような操作が可能です。例えばkawa.txtというファイルの5行目を表示するには以下のようにします。

 

$ sed -n 5p kawa.txt

teshio   256km  5590km2

 

出力を制限する「-n」オプションを追加してアドレスを指定すると、マッチした行だけが出力されます(デフォルトでは処理されなかった行がそのまま出力されます)。ここで “p” は「出力」を意味する “print” の頭文字です。

同様にして「5~8行目を表示する」という操作も可能です。

 

$ sed -n 5,8p kawa.txt

teshio 256km 5590km2
kitakami 249km 10150km2
abukuma 239km 5390km2
kiso 229km 9100km2

 

アドレスを「\$」とするとファイルの最終行が表示されます。「$」は最後の番号を意味し、シングルクォーテーションを使わない場合はバックスラッシュで「$」をエスケープする必要があります。

 

$ sed -n \$p kawa.txt

tenryu   212km  5050km2

 

シングルクォーテーションには中身の文字をそのまま単なる文字列として扱う機能があるため、アドレス指定の部分をシングルクォーテーションで囲んで「’$p’」とすればバックスラッシュは不要です(「’\$p’」とするとエラーになります)。

なお、このコマンドはtailコマンドで行数を指定して出力させた場合と同じです。

 

$ tail -n 1 kawa.txt

tenryu   212km  5050km2

(↑同じ出力)

grepコマンドでは行数を指定して出力させる操作が難しいので、そういうときはsedコマンドが活躍します。

 

「最終行から上にn番目の行」?

例えば、最終行から上の4行を消去・置換したいなどというとき、「$」が最終行の行番号を表すからといって安直に「$-4」などとしてはいけません。動きません。

 

$ wc -l kawa.txt

 

とするとkawa.txtというファイルに改行コードが何個存在するかを出力してくれるので、+1すれば行数になります。これを使ってシェルを書くなり何なりする必要があります。

 

因みに単に表示したいだけならtailコマンドを用いて「tail -n 4 kawa.txt」とすれば事足ります。

 

 sedコマンドで文字列を消去

sedコマンドに最も期待されている機能が文字列の置換と消去でしょう。消去のコマンドは比較的簡単で、これまで見てきた「p」コマンドの部分を「d」(delete)に変えるだけです。

 

$ sed 5d kawa.txt

 

このとき、「-n」は付けないことに注意しましょう。「-n」オプションはsedコマンドによって何らかの処理が施された行のみを表示するオプションであるため、消去した行を表示しようとしても何も表示されません。

ここで注意して頂きたいのが、このコマンドを使ったからといって「kawa.txt」というファイルの中身は何ひとつ変わっていない、ということです。dコマンドは出力でのみ特定文字を含む行を消去するという機能をもっています。

もし元ファイルの中身を変える、つまり、上書きしたいときは「-i」オプションを利用します。

 

$ sed -i 5d kawa.txt

$ cat kawa.txt
sinano   367km 11900km2
tone     322km 16840km2
ishikari 268km 14330km2
tadami   260km  2260km2
kitakami 249km 10150km2
abukuma  239km  5390km2
kiso     229km  9100km2
mogami   229km  7040km2
tenryu   212km  5050km2

 

catコマンドでkawa.txtの中身を見てみると、ちゃんと “teshio” の行が無くなっていますね。上書きするために「-i」オプションを利用することはそれなりにありますが、元のファイルの行数などが変わるので使いどころには気を付ける必要があります。

このdコマンドはpコマンドと同様に複数行にわたって適用できます(※練習の際はkawa.txtの中身は作り直すか、コピーしてお使い下さい・・・)

 

$ sed -i 5,8d kawa.txt

$ cat kawa.txt
sinano 367km 11900km2
tone 322km 16840km2
ishikari 268km 14330km2
tadami 260km 2260km2
mogami 229km 7040km2
tenryu 212km 5050km2

 

確かに5~8行目が除かれていますね。

「-i」オプションで上書きできると説明しましたが、それならリダイレクトでも上書きできるのではないか、と思った方もいるかもしれません。コマンドによっては同時に読み書きできるものもあるかもしれませんが、sedの場合、ファイル(もしくは標準入力)の読み込みと同時に出力されるので、以下のようにリダイレクトするとファイルの中身が消えてしまいます。

 

$ sed 5,8d kawa.txt > kawa.txt

$ cat kawa.txt
         (←何も表示されない)

 

このように何もでてきません。初心者のうちはsedで色々いじる前に対象ファイルのバックアップを取っておくことを強くお勧めします。

 

 

 sedコマンドで文字列を置換

sedコマンドで置換する際の基本的な書式は以下のようになります。

 

$ sed s/検索文字列/置換文字列/ ファイル名

 

“s” というコマンドは英語で「置換」を意味する “substitute” 表しています。これを使って “km” を “kilometer” に置換してみましょう。

 

$ sed s/km/kilometer/ kawa.txt

sinano   367kilometer 11900km2
tone     322kilometer 16840km2
ishikari 268kilometer 14330km2
tadami   260kilometer  2260km2
teshio   256kilometer  5590km2
kitakami 249kilometer 10150km2
abukuma  239kilometer  5390km2
kiso     229kilometer  9100km2
mogami   229kilometer  7040km2
tenryu   212kilometer  5050km2

 

すべての行で “km” → “kilometer” と置換されていますね。しかしすべての”km”が置換されている訳ではなく、”km” という文字列を含む行の最初の “km” だけが置換されています。2回目に出てきた “km” を置換するときはコマンドの最後に「2」を付けます。

 

$ sed s/km/kilometer/2 kawa.txt

sinano   367km 11900kilometer2
tone     322km 16840kilometer2
ishikari 268km 14330kilometer2
tadami   260km  2260kilometer2
teshio   256km  5590kilometer2
kitakami 249km 10150kilometer2
abukuma  239km  5390kilometer2
kiso     229km  9100kilometer2
mogami   229km  7040kilometer2
tenryu   212km  5050kilometer2

 

また、すべての該当する文字列を置換するには

 

$ sed s/検索文字列/置換文字列/g ファイル名

 

というようにコマンドの最後に「g」を付けます。

 

$ sed s/km/kilometer/g kawa.txt

sinano   367kilometer 11900kilometer2
tone     322kilometer 16840kilometer2
ishikari 268kilometer 14330kilometer2
tadami   260kilometer  2260kilometer2
teshio   256kilometer  5590kilometer2
kitakami 249kilometer 10150kilometer2
abukuma  239kilometer  5390kilometer2
kiso     229kilometer  9100kilometer2
mogami   229kilometer  7040kilometer2
tenryu   212kilometer  5050kilometer2

 

すべての “km” が置換できましたね。

見栄えに配慮して、数字と単位の間にスペースを入れたいときもsedコマンドが活躍します。

 

$ sed "s/km/ km/g" kawa.txt

sinano   367 km 11900 km2
tone     322 km 16840 km2
ishikari 268 km 14330 km2
tadami   260 km  2260 km2
teshio   256 km  5590 km2
kitakami 249 km 10150 km2
abukuma  239 km  5390 km2
kiso     229 km  9100 km2
mogami   229 km  7040 km2
tenryu   212 km  5050 km2

 

このとき、置換後の文字列に空白が含まれるため、ダブルクォーテーション(またはシングルクォーテーション)で囲んでおく必要があります。もし囲んでいないと “s/km/” と “km/g” が別々のオプションと見なされてしまい、正しく作動しません。

●   ●   ●

・「’」と「”」の使い分け

ダブルクォーテーションとシングルクォーテーションの使い分けは、中身の文字がシェルにとって意味があるもの(予約文字など)かどうかで決まります。

例えば、河川名の後に変数で指定した文字列を入れたいときはどちらで囲むかで結果が変わってきます。ここでは例としてsetコマンドで「ex」という名前の変数に “-gawa” という文字列を入れています。

(ダブルクォーテーションを使った場合)

$ set ex="-gawa" ; sed "s/ /${ex} /" kawa.txt

sinano-gawa   367km 11900km2
tone-gawa     322km 16840km2
ishikari-gawa 268km 14330km2
tadami-gawa   260km  2260km2
teshio-gawa   256km  5590km2
kitakami-gawa 249km 10150km2
abukuma-gawa  239km  5390km2
kiso-gawa     229km  9100km2
mogami-gawa   229km  7040km2
tenryu-gawa   212km  5050km2

 

(シングルクォーテーションを使った場合)

$ set ex="-gawa" ; sed 's/ /${ex} /' kawa.txt

sinano${ex}   367km 11900km2
tone${ex}     322km 16840km2
ishikari${ex} 268km 14330km2
tadami${ex}   260km  2260km2
teshio${ex}   256km  5590km2
kitakami${ex} 249km 10150km2
abukuma${ex}  239km  5390km2
kiso${ex}     229km  9100km2
mogami${ex}   229km  7040km2
tenryu${ex}   212km  5050km2

 

このように、シングルクォーテーションは中身を文字列としてしか扱わないので「${ex}」は変数ではなく単なる文字列として出力されてしまっています。

「’」と「”」にはそれぞれどのような特徴があるのかをしっかり理解しておかないと、思わぬバグの原因になってしまうこともあるので要注意です。

●   ●   ●

・置換したい文字列が「/」を含むとき

今まで紹介してきたsedコマンドの置換の書式は、

 

$ sed s/検索文字列/置換文字列/ ファイル名

 

のように、「/」によって区切られていましたが、特にスラッシュである必要はありません。「@」や「#」などでも代用できますし、「a」や「1」のような英数字でも区切ることが可能です。

(「@」の場合)

$ sed "s@km.@ @g" kawa.txt

sinano   367 11900 (「/」のときと同じです)
tone     322 16840
ishikari 268 14330
tadami   260  2260
teshio   256  5590
kitakami 249 10150
abukuma  239  5390
kiso     229  9100
mogami   229  7040
tenryu   212  5050

(「#」の場合)

$ sed "s#km.# #g" kawa.txt

sinano   367 11900 (「/」のときと同じです)
tone     322 16840
ishikari 268 14330
tadami   260  2260
teshio   256  5590
kitakami 249 10150
abukuma  239  5390
kiso     229  9100
mogami   229  7040
tenryu   212  5050

(「a」の場合)

$ sed "sakm.a ag" kawa.txt

sinano   367 11900 (「/」のときと同じです)
tone     322 16840
ishikari 268 14330
tadami   260  2260
teshio   256  5590
kitakami 249 10150
abukuma  239  5390
kiso     229  9100
mogami   229  7040
tenryu   212  5050

 

使えない文字としては特殊文字の「!」や「$」などでしょうか。ただ、ほとんどの文字で代用可能なので、検索対象や置換後の文字列にスラッシュが含まれている場合は区切り文字を「/」以外のあまり紛らわしくない文字にしましょう。

●   ●   ●

・「&」や「\」で置換したいとき

「&」(アンド)はsedのオプション中では検索で該当した文字列を表しており、「\」(バックスラッシュ)は特殊文字をエスケープするための記号なので、単体では表示できません。

これらの文字は「\&」や「\\」のようにエスケープしておく必要があります。

(例)

$ sed "s/km/\\/g" kawa.txt

sinano   367\ 11900\2
tone     322\ 16840\2
ishikari 268\ 14330\2
tadami   260\  2260\2
teshio   256\  5590\2
kitakami 249\ 10150\2
abukuma  239\  5390\2
kiso     229\  9100\2
mogami   229\  7040\2
tenryu   212\  5050\2

 

意外と忘れやすく、バグの原因になることがあるので注意です。

 

 

 sedコマンドで文字列を追加・挿入

sedコマンドでは文字列を任意の場所に追加したり挿入したりすることができます。「i」は挿入(前の行に入れる)、「a」は追加(後ろの行に付け足す)を意味します。行番号を指定しなければすべての行が操作対象となります。

 

$ sed "1i \ *nihon-no-kawa Top10*" kawa.txt

 *nihon-no-kawa Top10*
sinano   367km 11900km2
tone     322km 16840km2
ishikari 268km 14330km2
tadami   260km  2260km2
teshio   256km  5590km2
kitakami 249km 10150km2
abukuma  239km  5390km2
kiso     229km  9100km2
mogami   229km  7040km2
tenryu   212km  5050km2

※行頭の空白はスペースをエスケープすることで表示できます。

 

$ sed a----------------------- kawa.txt

sinano   367km 11900km2
-----------------------
tone     322km 16840km2
-----------------------
ishikari 268km 14330km2
-----------------------
tadami   260km  2260km2
-----------------------
teshio   256km  5590km2
-----------------------
kitakami 249km 10150km2
-----------------------
abukuma  239km  5390km2
-----------------------
kiso     229km  9100km2
-----------------------
mogami   229km  7040km2
-----------------------
tenryu   212km  5050km2
-----------------------

 

●   ●   ●

・該当行or指定行の先頭or末尾に文字列を追加する

正規表現の「^」は行頭、「$」行末を表します。環境によっては「-e」オプションは付けなくても動きますが、付けておいた方が無難です。

(行指定なしバージョン)

$ sed -e 's/^/:/g' kawa.txt

:sinano   367km 11900km2
:tone     322km 16840km2
:ishikari 268km 14330km2
:tadami   260km  2260km2
:teshio   256km  5590km2
:kitakami 249km 10150km2
:abukuma  239km  5390km2
:kiso     229km  9100km2
:mogami   229km  7040km2
:tenryu   212km  5050km2

 

(行指定ありバージョン)

$ sed '3s/^/:/g' kawa.txt

sinano   367km 11900km2
tone     322km 16840km2
:ishikari 268km 14330km2  (←3行目だけ追加)
tadami   260km  2260km2
teshio   256km  5590km2
kitakami 249km 10150km2
abukuma  239km  5390km2
kiso     229km  9100km2
mogami   229km  7040km2
tenryu   212km  5050km2

 

(末尾:行指定ありバージョン)

$ sed -e '2s/$/ :largest catchment area/g' kawa.txt

sinano   367km 11900km2
tone     322km 16840km2 : the largest catchment area
ishikari 268km 14330km2
tadami   260km  2260km2
teshio   256km  5590km2
kitakami 249km 10150km2
abukuma  239km  5390km2
kiso     229km  9100km2
mogami   229km  7040km2
tenryu   212km  5050km2

●   ●   ●

・特定の文字列を含む行を丸ごと置換したいとき

特定の文字列を含む行全体を置換するにはcコマンドを使います。

 

$ sed -e '3cISHIKARI 268km 14330km2' kawa.txt

sinano   367km 11900km2
tone     322km 16840km2
ISHIKARI 268km 14330km2
tadami   260km  2260km2
teshio   256km  5590km2
kitakami 249km 10150km2
abukuma  239km  5390km2
kiso     229km  9100km2
mogami   229km  7040km2
tenryu   212km  5050km2

(3行目を “ishikari” が大文字である行に置換しました)

 

 Tips1:空行を削除する

行頭から行末まで何もないような行を検索すればよいので次のような記法になります。(※ここで「^」は行頭、「$」は行末の意味)

 

$ sed '/^$/d' ファイル名

 

 Tips1:空行を削除するTips2:複数の置換・追加を同時に行う

「-e」オプションによるコマンドを複数個併記すると並列的に置換・追加できます。

 

$ sed -e '3s/$/ @ Hokkaido/' -e '5s/$/ @ Hokkaido/' kawa.txt

sinano   367km 11900km2
tone     322km 16840km2
ishikari 268km 14330km2 @ Hokkaido
tadami   260km  2260km2
teshio   256km  5590km2 @ Hokkaido
kitakami 249km 10150km2
abukuma  239km  5390km2
kiso     229km  9100km2
mogami   229km  7040km2
tenryu   212km  5050km2

 


以上、sedコマンドの様々な機能を紹介してきましたが、これだけ豊富な編集機能が備えているということを知っていれば「sed」が「stream editor」の略だというのも頷けますね!

sedコマンドは使い方次第ではファイル処理作業を劇的に省力化してくれます。今回紹介していないオプションや使用法も沢山ありますので、是非勉強してみてください!

 

 

“【Linux入門】sedコマンドの基本を学ぶ” への1件の返信

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です