シナプス技術者ブログ

シナプスの技術者公式ブログ。インターネットで、鹿児島の毎日を笑顔にします。

sedコマンドについて学習してみました

初めまして、シナプスの技術部ネットワーク課の岩元と申します。 未経験で入社し、現在シナプスのインフラエンジニアとしてお仕事をさせて頂いております。

私自身サーバを扱った経験がなく、しばらく Linux について勉強しているなかで、 sed コマンドというものを知り、大変便利だと感じました。エンジニアの界隈では、多数の人たちに理解あるコマンドかと思いますが、 自分が初心者ということもあり、備忘録も兼ねて今回sedについて学んだことをまとめてみました。

sed コマンドのオンラインマニュアル www.gnu.org

sed の基本情報

sedコマンドはフィルタを作成したり、エディタを開かずにファイルを直接編集できる、とても有用なコマンドです。 標準入力から受け取ったデータを編集し、標準出力に書き出します。

書式・オプション・コマンドについて以下にまとめます。

書式
  • sed [オプション] コマンド [ファイル]
  • sed [オプション] -e コマンド1 [ -e コマンド2 ... ] [ファイル]
  • sed [オプション] -f スクリプト [ファイル]
主なオプション
オプション 意味
-e 処理内容を指定する。コマンドを続けて指定する場合に必須のオプション
-i 処理した内容でファイルを上書きする
-n 編集した各行の自動出力をさせない(p コマンドとの併用時に設定可能)
-f コマンドが書かれたスクリプトファイルを指定する
-E , -r 拡張正規表現を使う
編集コマンド

置換・表示・削除などの操作を指定するためのコマンドです。

sed の基本操作

sed の置換機能について

sed で最もよく使われる操作が置換機能です。 s/old/new/ という置換用の編集コマンドは "/" で囲んだ2つの文字列のうち、左側の文字列を右側の文字列に置き換えることができます。 各行につき1番目に見つけた最初の文字列のみ置換ができます。

# cat sample01.txt
old  old  old
old  old  old

# sed -e 's/old/new/' sample01.txt
new  old  old
new  old  old

gコマンドを付与し、s/old/new/g とすることで、1行の中で見つけた文字列を全て置換させることができます。

# sed -e  's/old/new/g' sample01.txt
new  new  new
new  new  new

sed の出力内容の制御

"-n" というオプションを付けると、編集した結果を出力させないようにできます。

# cat sample02.txt
old
000 111
aaa bbb

# sed -n -e 's/old/new/g' sample02.txt
#               <- 何も表示されない

"-n"と一緒に print(出力しなさい) という意味のコマンド"p"を使うことで、編集した対象の行のみを 表示させることができます。(対象外の余分な行は出力を非表示にできます)

# sed -e 's/old/new/g' sample02.txt
new             <- 編集対象の行
000 111         <- 余分な行
aaa bbb         <- 余分な行

# sed -n -e 's/old/new/gp' sample02.txt
new             <- 編集対象の行のみ出力される

デリミタについて

置換コマンドで、区切りに使う “/”(スラッシュ) という文字を「デリミタ」と呼びます。 置換したい文字列内に"/"がある場合は、デリミタと解釈されないように "\ /" としてエスケープさせると良いのですが、 "/"が多用に含まれてしまうと視認性が下がるため、 デリミタの文字を、他の文字に変えて表記する場合もあります。(下記の例では"@"を使用)

# cat  sample03.txt
who command: file
/var/log/wtmp

# sed  -e  's@/var/log/wtmp@/var/run/utmp@' sample03.txt
who command: file
/var/run/utmp

基本的なコマンド例

ここでは、ファイルの編集でよく使うコマンドの例を紹介していきます。

置換機能を利用した編集例
  • 「old」という文字列の削除
    sed -e 's/old//g' file

  • 行頭の「oldtext」という文字列を削除
    sed -e 's/^oldtext//' file

  • 行末の「oldtext」という文字列を削除
    sed -e 's/oldtext$//' file

  • 行頭に文字列「add」を追加
    sed -e 's/^/add/' file

  • 行末に文字列「add」を追加
    sed -e 's/$/add/' file

正規表現を使った編集例
  • 行頭から3文字をすべて削除
    sed -e 's/^...//' file

  • 行の全てを「abcd」という文字列に置換
    sed -e 's/.*/abcd/' file

  • 「s」という文字まで削除
    sed -e 's/.*s//' file

  • 括弧の中の文字列を削除
    sed -e 's/(.*)/()/' file

  • 1~9までの数字を0に置換
    sed -e 's/[1-9]/0/g' file

  • 英字(小文字)を削除
    sed -e 's/[a-z]//g' file

行単位の編集例
  • 1~4行目を対象に置換
    sed -e '1,4s/oldtext/newtext/g' file

  • 5行目から最終行までを対象に置換
    sed -e '5,$s/oldtext/newtext/g' file

  • キーワードによる行の指定
    例) "begin"を含む行から、"end"を含む行までを削除
    sed -e '/begin/,/end/d' file

dコマンドの例
  • 1行目を削除
    sed -e '1d' file

  • 1~4行目まで削除
    sed -e '1,4d' file

  • 空白の行を削除
    sed -e '/^$/d' file

pコマンドの例
  • 2行目だけを表示
    sed -n '2p' file

  • 最初の行から5行目までを表示
    sed -n '1,5p' file

  • 最終行を表示
    sed -n '$p' file

応用的な sed の使い方

少々応用的ですが、sed コマンドを業務で活用する際に、知っておくことで大変便利だと感じた使い方について紹介していきます。

ホワイトスペースの処理

ホワイトスペースとは、タブや、スペースのような空白文字のことです。 タブが入っているのか、スペースが入っているのか分からない状態でも、 以下のコマンドを実行することで、まとめてホワイトスペースを削除できます。

sed -e 's/[ \t]\+//g' file
sed -e 's/\s\+//g' file

・実行例

# cat whspace.txt
He               ll     o,      I                         m
          sy            nap                     s        e
 e                ngi            n     e                er          !
# sed -e 's/[ \t]\+//g' whspace.txt
Hello,Im
synapse
engineer!

正規表現 [ \t]の、(" ")は spaceキー、(\t)は tabキーを意味しております。
タブとスペースの混在を意味する上記の"[ \t]"や、ホワイトスペースそのものを意味する"\s"を正規表現で使うことで、まとめて処理させることができます。

ファイルの上書き

"-i " オプションで、編集した結果を、対象のファイルに上書きさせることができます。

sed -i '/oldtext/d' file

「-i.org」のように、オプションの後ろに末尾名を付けることで、その末尾名が付いたバックアップファイルを作成しておくことも可能です。

sed -i.org '/oldtext/d' file

・実行例

# cat test.txt
oldtext
newtext

# ls -l test.*
-rw-r--r-- 1 root root 16 Sep 27 19:24 test.txt

○バックアップ作成と編集を同時に実行
# sed -i.org '/oldtext/d' test.txt

○ファイル確認
# ls -l test.*
-rw-r--r-- 1 root root  8 Sep 27 19:26 test.txt
-rw-r--r-- 1 root root 16 Sep 27 19:24 test.txt.org
    ↑末尾が「.org」のバックアップファイルが保存されている

# cat test.txt
newtext

# cat test.txt.org
oldtext
newtext
↑編集前のファイルの中身が残っている

改行コードの変換

Windows や、MacOS、Linux(Unix)では、以下のように使用する改行コードが異なります。

OS 改行コード 正規表現
Unix LF(ラインフィールド) \n
Mac(OSX) LF(ラインフィールド) \n
Mac (OS9) CR(キャリッジリターン) \r
Windows CR+LF \r\n

「od -c」コマンドで、ファイルに使われている改行コードを確認することができます。 例えば、以下のファイルは改行コードが"\r"と"\n"で表示されているので、CR+LFであることが分かります。

# od -c winline.txt
0000000 a b c d e \r \n f g h i j \r \n k l
0000020 m n o \r \n p q i s t \r \n u v w x
0000040 y z \r \n
0000044

Linux に対応した改行コードに変換させる時は、CR+LF を LFに変換させればよいので、sed コマンドで"\r"を削除してあげることで解決できます。

sed -i 's/\r//g' winline.txt

・実行例
# sed -i 's/\r//g' winline.txt
# od -c winline.txt
0000000 a b c d e \n f g h i j \n k l m n
0000020 o \n p q i s t \n u v w x y z \n
0000037

その他、各改行コードの変換は以下の通りです。

  • CR+LF を CRに変換
sed -i 's/\n//g' file
  • LF をCR+LFに変換
sed -i 's/$/\r/g' file

異なる階層で複数のファイルを一括編集

以下のようなディレクトリの階層と、ファイルが存在しているとき、

# tree  --charset=C
.
|-- dir1
|   |-- 1.txt
|   `-- dir11
|       |-- 11.exe
|       |-- 11.img
|       `-- 11.txt
|-- dir2
|   |-- 2.img
|   `-- 2.txt
`-- dir3
    |-- 3.img
    `-- 3.txt

4 directories, 8 files

# cat dir1/1.txt
12345

# cat dir1/dir11/11.txt
12345

# cat dir2/2.txt
12345

# cat dir3/3.txt
12345

末尾が「.txt」のファイルを一括して編集したい場合、sed に find コマンドと、xargs コマンドを組み合わせることで、まとめて編集できます。

find . -type f -name "*.txt" | xargs sed -i '<編集コマンド>'

・実行例

find . -type f -name "*.txt" | xargs sed -i 's/[1-5]/N/g'

# cat dir1/1.txt
NNNNN

# cat dir1/dir11/11.txt
NNNNN

# cat dir2/2.txt
NNNNN

# cat dir3/3.txt
NNNNN

xargs は、コマンドの実行結果を、次のコマンドの引数に受け渡すことができます。 「find . -type f -name "*.txt"」により、検索された「.txt」のファイルのリストを、パイプ先の sed コマンドの引数に引き渡すことで、対象のファイルを編集することができます。

参考書籍

今回、Linux のシェルについて学習するにあたり、以下の書籍を参考に学習しました。

こちらの書籍ですが、実務で活用するコマンドや、シェル関数・シェルスクリプトの書き方についてとても詳しく解説しており、 私のような初心者には勿論のこと、仕事に慣れた中級者の方々ににも大変オススメの書籍です。

まとめ

  • コマンドの一つ一つの意味を深く学習したことで、様々な使い方について学ぶことができました。
  • sedコマンドは実務で活用できる、大変便利なコマンドですので、Linux 初心者の方たちに是非おすすめです。
  • 私自身まだまだ慣れていない部分も多いですが、サーバの運用をしていく上で、今回学んだことを日々の業務でも活かせるようにしたいと思います。