2009/12/24

sedコマンドの使い方 #solaris #unix #sed

本業のからみで、sedコマンドの使い方を人に教えることになったので。せっかくだから書き出したものをblogにも転載しておくことにした。

結構、マニアックではあるけれど、テキストファイルを一括修正する, 表記ゆれを直すなど色々と使い道のある良いコマンドなので、覚えておくUNIXエンジニアとしてはシアワセだと思う。

ちなみにsedを使いこなすには正規表現は必須のスキルになる。幸いにして書き方それ自体はWebをちょと検索すればゴロゴロ出てくるし、自分の書いた正規表現をチェックしてくれるstrfriendなんてサービスもある。なにより、sedに限らず、grep, vi……その他、その他、正規表現が扱えるだけで生産性を劇的に上げてくれるツールには事欠かないのがUNIXなんである。これを機会にちょっとお試し頂いて、快適UNIXライフを送っていただきたい次第なんである。

sedコマンドの基本書式

sedの基本書式は:

sed 'Script' SourceFile
Script
エディタコマンド。書式は後述。
SourceFile
入力元のテキストファイル。

であり、SourceFileで指示されたファイルから内容を読み取り、Scriptを適用した結果を、標準出力に書き出す。

入力はファイルを指定するのではなく、標準入力から読み込ませることもできる。その場合には:

cat /foo/bar | sed 'Script'

このようなカタチになる。この場合はファイル/foo/barをcatした結果を、標準入力から読み込んでScriptを適用した結果を標準出力に 書き出す。

処理した結果を、ファイルに書き出したい場合には:

sed 'Script' SourceFile > /foo/bar

このようにすれば良い。この場合はSourceFileで指示されたファイルから内容を読み取り、Scriptを適用した結果を、ファイル/foo /barに書き出す。

なおオプションにより、次のようなこともできる。

-e
続く文字列がScriptであることを明示的に指示する。これを指示することで、複数のScriptを一 度に適用することもできる。なお-fオプションを指定せず、かつScriptが一つの場合には省略しても構わない。
-f
続き文字列がファイル名であることを明示的に指示する。これを指示することで複数のファイルを一度に処理することもできる。処理対象のファイ ルが一つの場合には省略しても構わない。

-e と -f は、それぞれ複数個を指定できる。その場合、Scriptは指定された順序で適用される。

Script

Scriptの基本書式は:

[ address [ , address ] ] command [ arguments ]

上記の通りになる。

address
正規表現(man regexpも参照のこと)で構成される。 addressの指示が一つの場合には、その正規表現と一致する行を処理対象にする。addressの指示が二つの場合には最初のaddressと一致し た箇所から、二つ目のaddressが一致する箇所までを処理対象にする。

command
対象のテキストに対して行う処理を指示する。コマンドの詳細はman sedを参照のこと。主要なものは 後述する。

arguments
commandに対して与える引数。

commandのうち、主要なものは下記の通り。

a\ text
textを末尾に追加する
d
正規表現にマッチした箇所を削除する
c\ text
正規表現にマッチした箇所を削除し、テキストを追加する
i\ text
正規表現にマッチした箇所の冒頭にtextを追加する
s/RegularExpression/Replacement/flags
正規表現RegularExpressionにマッチした箇所を、Replacementで置き換える。主なflagは次の通り:
省略
RegularExpressionに最初に一致した箇所を置き換える。
n
RegularExpressionにn番目に一致した箇所を置き換える。nは1〜512の間の整数でなければならない。
g
RegularExppressionに一致した箇所すべてを置き換える

sedコマンドの使い方の例

次の例は変数NMで指示されたユーザの情報を/etc/passwdから読み取り、passwdファイル中 に"x"と表記されているパスワードを変数PASSに置き換えて、NIS用のpasswdファイル (${YPMAP}/passwd)にエントリを追加している。

 grep "^${NM}:" /etc/passwd | \
   sed "s:\:x\::\:${PASS}\::" >> ${YPMAP}/passwd 

単純な文字列置き換えの事例として読み取れる。なお変数PASSは、予め:

PASS=`grep "^${NM}:" /etc/shadow | \
   cut -d":" -f2`

このようなカタチで、/etc/shadowから該当ユーザのパスワード(暗号化済み)を取り出して設定してある。また変数NMは、 実際には予め定義してあるリストを使いforeachなどのイテレータで処理させることを想定している。

次の例は、NISのMakefileを書き換える。具体的にはPWDIR =で始まる行をPWDIR = ${YPMAP}(YPMAPはNISデータベースの配置先, /var/yp/map など)に書き換えている。

sed "/^DIR *=/s:^.*$:DIR = ${YPMAP}:" ${YPMKFL}.org | \
   sed "/^PWDIR *=/s:^.*$:PWDIR = ${YPMAP}:" > ${YPMKFL}  

次の例はman sedに示されている事例の引用。BSD系のcat -sコマンドと同様の動作をし、標準入力から余分な空白行を圧縮する。

かなり凝った内容になっているが、ここから:

  • Scriptは複数行に渡ってもよい
  • Scriptに含まれる'#'で始まる行はコメント行として扱われる

ということが読み取れる。

sed -n '
      # Write non-empty lines.
      /./     {
              p
              d
              }
      # Write a single empty line, then look for more empty lines.
      /^$/
        p
      # Get next line, discard the held  (empty line),
      # and look for more empty lines.
      :Empty
      /^$/        {
              N
              s/.//
              b Empty
              }
      # Write the non-empty line before going back to search
      # for the first in a set of empty lines.
              p
      '

blog comments powered by Disqus