いますぐ実践! Linuxシステム管理

いますぐ実践! Linux システム管理 / Vol.224 / 読者数:2174名

こんばんは、うすだです。

ここ数日で、あっという間にセミが鳴き出し、 空気が蒸し暑くなってきたように思いますが、みなさまの地域ではいかがでしょうか。

セミの幼虫ががんばって木に登ろうとしていると、がんばれあともう少しだ! …なんて応援したくなりますが、いざ成虫になると、 うっとおしいとしか思わなくなります。ニンゲンなんて勝手な生き物ですね。

…いえ、そう思うのは私だけかもしれないのに、 ニンゲンというカテゴリで大きくまとめようとしてしまいました。

実は、今週、ひとによって考えていることが違うということ、 自分の考えが一般的とは限らないということを、何度も指摘されることがあり、 少々…いえ、結構大きく反省しているところです。

それについては、あとがきで詳しく述べたいと思います。
また、何があったかは、次回に述べさせていただきます。

ややもったいぶってますが、今回もはりきってまいりましょうか。

今回のお題 - ファイルを比較する

環境が変わったり、バージョンアップしたりすると、 それに合わせて設定を変える必要が生じます。

そのとき行った変更を、別のサーバへ反映させたりする際には、変更内容を把握して、 その変更だけを実施する必要がありますよね。

また、あるサーバだけうまく動かない、といったときには、 同様に動作をしているサーバの設定と比較するなどして、 原因を追求する必要が生じるのではないかと思います。

そんなとき、画面上に設定ファイルを並べて表示して見比べたりしても、 そうそう違いがわかるものではありません。
設定ファイル同士の差分を確認したり、 デフォルトの設定との差分を比較したりするなどして、 わかりやすい形に変えてから行う必要があります。

というわけで今回は、いろいろなファイルをどうかして比較する方法を、 いくつかご紹介したいと思います。

diff なら知ってるわ…と削除ボタンを押す前に、 いちおうさらっと目を通していただけますと幸いです。 (ちょっとだけひねりましたので…)

テキストファイルを単純に比較する

とか言いながら、まずはテキストファイルを比較するということで、 多大にお世話になるのが「diff」コマンドです。
テキストファイルを行単位で比較し、差分を出力してくれます。
たとえば、 postfixの設定ファイル /etc/postfix/main.cf のバックアップファイル main.cf.bak と、現在の設定内容を比較するには、以下のように実行します。

  $ diff /etc/postfix/main.cf.bak /etc/postfix/main.cf
  30c30
  < myhostname = localhost
  ---
  > myhostname = myserver
  38a39,43
  > 
  > smtpd_sasl_auth_enable = yes
  > smtpd_recipient_restrictions = permit_mynetworks, \
  permit_sasl_authenticated, check_relay_domains, reject
  > 
  > transport_maps = hash:/etc/postfix/transport

main.cf.bakからどの行を削除し、どの行を追加するとmain.cfになるのかを、 上記のように出力してくれます。
ちなみに、先頭が「<」の行が削除する行、「>」の行が追加する行です。

「-u」オプションをつけて実行すると、 周囲の行も含めてもう少しわかりやすく出力してくれます。

  $ diff -u /etc/postfix/main.cf.bak /etc/postfix/main.cf
  --- main.cf.0	2011-11-05 10:07:34.759301834 +0900
  +++ main.cf	2012-06-03 13:48:00.809307065 +0900
  @@ -27,7 +27,7 @@
   # See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for
   # information on enabling SSL in the smtp client.
 
  -myhostname = localhost
  +myhostname = myserver
   alias_maps = hash:/etc/aliases
   alias_database = hash:/etc/aliases
   mydestination = tamao, tamaoh, localhost.localdomain, localhost
  @@ -36,3 +36,8 @@
   mailbox_size_limit = 0
   recipient_delimiter = +
   inet_interfaces = all
  +
  +smtpd_sasl_auth_enable = yes
  +smtpd_recipient_restrictions = permit_mynetworks, \
  permit_sasl_authenticated, check_relay_domains, reject
  +
  +transport_maps = hash:/etc/postfix/transport

この場合、「-」が削除する行、「+」が追加する行です。
また、比較するファイルがCのソースやPerlなどのスクリプトの場合は、 「-p」オプションもつけると、さらにわかりやすく出力してくれます。
(どうわかりやすいかは、実際に実行してみてくださいませ。)

 

ところで、-uオプションの出力結果は、 「patch」というコマンドで差分を反映できる形式になっています。
patchコマンドは、diffコマンドで作成した差分の内容を、 多少の誤差(?)を考慮した上で反映してくれるものです。

たとえば、上記の差分を別のサーバへ反映するには、 以下のように patch を実行します。

  $ diff -u main.cf.bak main.cf > main.cf.diff
  別のサーバ# cd /etc/postfix
  別のサーバ# patch -p0 -b -z .bak < /some/where/main.cf.diff

上記の場合、main.cf.diff というパッチファイルを作成し、 それを別のサーバへ持ってきて、patch コマンドで使用しています。
カレントディレクトリの main.cf に対してパッチを適用し、 .bak を付加した名前でバックアップファイルを残しています。

patchコマンドが見当たらない場合は、 同名のパッケージをインストールしてみてください。
(RedHat系なら「yum install patch」、 Debian系なら「apt-get install patch」とか実行してみてください。以降も同様です。)

文字コードが違う場合

同じテキストファイルでも、文字コードが違うと、 その部分は全部違う行として認識されてしまいます。
そんなときは、文字コードを合わせてから比較する必要があります。

たとえば、一方が「UTF-8」でもう一方が「Shift-JIS」で記述されているとします。 単純に比較すると、以下のように全部が違うと言われます。
(Shift-JISのところは文字化けするため、 (文字化け)と表記しました。)

  $ cat UTF-8なファイル
  これはテストだよ
  日本語だよ
  $ cat SJISなファイル
  (文字化け)
  (文字化け)
  $ diff SJISなファイル UTF-8なファイル
  1,2c1,2
  < (文字化け)
  < (文字化け)
  ---
  > これはテストだよ
  > 日本語だよ

ですので、Shift-JISの方をUTF-8に変換してから比較しましょう。
(逆でも構いませんが、その場合、表示のときにやや困ります…。)

  $ iconv -f Shift-JIS -t UTF-8 SJISなファイル > 変換後のファイル
  $ diff 変換後のファイル UTF-8なファイル

 

また、Windowsで作成されたテキストファイルの場合、改行コードが違うため、 こちらもことごとく違う行として認識されてしまいます。

そんなときは、「dos2unix」コマンドで変換します。

  $ dos2unix < windowsのテキストファイル > 変換後のファイル

dos2unix は、同名のパッケージをインストールすると使えます。

その他形式などが違う場合

同じソフトの設定ファイルでも、書いたひとによって、 スペースやタブの入れ方がぜんぜん違ったりします。
たとえば以下の場合、スペースの個数の違いしかありませんが、 diff は違う行として認識します。

  $ diff test1.conf test2.conf
  2,6c2,6
  <     Options None
  <     AllowOverride None
  <     Order deny,allow
  <     Deny from all
  <     Allow from ::1/128 fd41:28b7:be11::/64
  ---
  >   Options None
  >   AllowOverride None
  >   Order deny,allow
  >   Deny from all
  >   Allow from ::1/128 fd41:28b7:be11::/64

こんなときは、「-b」オプションをつけて diff コマンドを実行します。
すると、スペースやタブの違いを考慮しなくなります。
(「-w」オプションの方がもっと考慮しなくなるようです。)

  $ diff -b test1.conf test2.conf
  $ 

 

記述されている順番に関係なく比較したい、ということもあります。
そんなときは、「sort」コマンドで、 双方のファイルをアルファベット順に並べ替えてから比較すると、 純粋に設定内容で比較できます。
(ただし、行単位で設定項目がある場合に限られます。 行内の設定の順番までは…という感じです。)

  $ sort test1.conf > test1-sort.conf
  $ sort test2.conf > test2-sort.conf
  $ diff test1-sort.conf test2-sort.conf

 

「#」以降はコメントなので省きたい、という場合は、 「sed」コマンドで取り除いてから比較します。

  $ sed 's/#.*$//' test1.conf > test1-nocomment.conf
  $ sed 's/#.*$//' test2.conf > test2-nocomment.conf
  $ diff test1-nocomment.conf test2-nocomment.conf

ただ、上記の結果が、空行だらけになってしまうかもしれません。
そんなときは、空行を削ってしまいましょう。

  $ sed -e 's/#.*$//' -e '/^ *$/d' test1.conf > test1-nospace.conf
  $ sed -e 's/#.*$//' -e '/^ *$/d' test2.conf > test2-nospace.conf
  $ diff test1-nospace.conf test2-nospace.conf

さらに、前述の sort も入れると、効率的かもしれません。

  $ sed -e 's/#.*$//' -e '/^$/d' test1.conf | sort > test1-n.conf
  $ sed -e 's/#.*$//' -e '/^$/d' test2.conf | sort > test2-n.conf
  $ diff test1-n.conf test2-n.conf

 

sed コマンドに関しては、下記でご紹介済です。
よろしければご覧くださいませ。

Vol.197 sed と正規表現でいろいろ自動化する
http://www.usupi.org/sysad/197.html

バイナリファイルを比較する

さて、テキストファイルは diff コマンドで比較できました。
では、バイナリファイルはどうやって比較すればよいでしょうか。

まず、「cmp」というコマンドがあります。 2つのファイルが同じかどうか確認してくれます。

  $ cmp test1.bin test2.bin
  test1.bin test2.bin 異なります: バイト 8、行 1

同じであれば何も言いませんが、違う場合、 上記のように違う場所の最初の情報を示してくれます。
「-l」オプションを指定すると、どの位置がどう違うのかを、全部示してくれます。

  $ cmp -l cmp test1.bin test2.bin
  8 357 377

8バイト目が、8進数でそれぞれ357と377で違うよ、とおっしゃってます。

ただ、どこかの位置のデータが異なるだけならよいのですが、 途中で余計なデータが挿入されている場合は、それ以降がすべて違うと言われ、 怒涛のごとく表示されてしまいます。

  $ cmp -l cmp test1.bin test2.bin
    8 357 377
    9 358 357
   10 359 358
  ...中略...怒涛のごとく違うと言われるよ...
  cmp: test1.bin でファイル終端 (EOF) に達しました

そんなときは、テキストファイルに変換してから比較します。
バイナリファイルをテキスト形式で出力するには、「od」コマンドを使用します。 1行につき1バイトのデータを出力して、それを diff コマンドで比較すれば、 データの挿入にも対応できます。
(「-v」オプションは省略せずに出力、 「-w」オプションは1行ごとに出力するバイト数の指定、 「-t」オプションはフォーマット指定です。)

  $ od -v -w1 -t x1 test1.bin
  0000000 3c
  0000001 44
  0000002 69
  ...後略...

ただ、これだとアドレスが表示されてしまいますので、 アドレスの部分を「awk」コマンドで消し去ります。

  $ od -v -w1 -t x1 test1.bin | awk '{print $2}' > test1.bin.txt
  $ od -v -w1 -t x1 test2.bin | awk '{print $2}' > test2.bin.txt
  $ diff test1.bin.txt test2.bin.txt
  50,51d49
  < 20
  < 20
  ...後略...

こんな感じで比較できました。上記の場合、 50バイト目から2バイトほどデータが取り除かれている、ということがわかります。

ちなみに、「hexdump」コマンドでも同様のことができます。

  $ hexdump -v -e '/1 "%02x\n"' test1.bin > test1.bin.txt
  $ hexdump -v -e '/1 "%02x\n"' test2.bin > test2.bin.txt
  $ diff test1.bin.txt test2.bin.txt
  ...後略...

hexdump コマンドは、RedHat系の場合は「util-linux」、 Debian系の場合は「bsdmainutils」というパッケージに入っています。

おわりに

以上、ファイルを比較する方法を、いくつかご紹介しました。

他にも、文字列だけ取り出して比較(stringsコマンド)や、 実行ファイルの場合(objdumpコマンドなど)など、いろいろな方法があります。

気になる貴兄は、コマンド名から自力で調べてみてください。
あるいは、ニーズがあれば、別途ご紹介します。

宿題の答え

前回の宿題は、

  watch で、一定の回数を実行したら終了するようにしてみましょう。

でした。

…試行錯誤の末、以下に至りました。
長くて申し訳ありませんが、ざざっと見ていただけますと幸いです。

#!/bin/sh
# カウントに一時ファイルを使う / 終了時に必ず消えていただく
TMPFILE=`mktemp /tmp/watch-nr-XXXXXX`
trap "rm -f $TMPFILE" 0 1 2 3 4 5 6 8 9 11 15
echo -n 0 > $TMPFILE

# 引数チェック
if [ $# -lt 2 ]; then
    echo "Usage: $0 nr watch_args..."
    exit 1
fi

# 第一引数が回数
NR="$1"
shift
# $ARGS にコマンド以外の引数、$COMM にコマンド
ARGS=""
while [ $# -gt 0 ]; do
    [ $# -eq 1 ] && COMM=$1 || ARGS="$ARGS $1"
    shift
done
# watch はバックグラウンドで動いていただく
watch $ARGS "\
    cnt=\$(cat $TMPFILE); \
    $COMM; \
    cnt=\$(expr \$cnt + 1); \
    echo -n \$cnt > $TMPFILE" &
# こちらで監視して終了させる
PID=$!
while [ "`cat $TMPFILE`" -lt "$NR" ]; do
    sleep 1
done
kill $PID

詳細はコメントを見てご理解いただくとして、ざっくりと説明します。

上記シェルスクリプトは、指定された回数 watch コマンドを実行させ、 その回数に達したら自動的に終了します。第1引数に実行回数を指定し、 第2引数以降はそのまま watch コマンドに渡します。

「mktemp」コマンドが作成する一時ファイルに実行回数を保存し、 watchコマンドをバックグラウンドで動かします。それと並行して、 メイン側で回数を定期的にチェックし、 指定された回数に達していればwatchを終了させます。

たとえば、上記を nwatch.sh というファイル名で保存したら、 いつものように実行権限をつけて実行してみましょう。

  $ chmod +x nwatch.sh
  $ ./nwatch.sh 10 -n 1 -d iostat

1秒毎に「iostat」コマンドが実行され、10回起動されると終了します… するはずです。

watch コマンドを実行する側と監視する側に分けたのは、 回数だけでなくいろんな条件で監視できると思ったからです。
(時間とか、コマンドの実行結果・出力結果などですね。)

細部を考慮した作りにはなっていないため、 本格的に使うにはいろいろと修正も必要かもしれません。その辺はご容赦くださいませ。

今回の宿題

今回の宿題は、

  テキストファイルならdiff、バイナリファイルならcmpで比較するもの
  を作ってみましょう。

です。

テキストファイルかバイナリファイルかを見分けて、 diff か cmp を実行するスクリプトを書けばよさそうですね。

また、いくつかの手段を試みて、出力結果がもっとも小さくなったものを出力する、 というのも面白いかもしれません。(自分の首をしめたかな…)

というわけで、試行錯誤してみてください。
(わたしもこれから試行錯誤します。)

あとがき

先週〜今週にかけて、仕事的には余裕がありましたが、重大な決断をする必要があり、 精神的には余裕のない日々を過ごしていました。

その間、いろいろな方とお話ししたり、ご意見を伺ったり、 自分の意見を説明したりしました。

その結果、わかったことがあります。

それは、自分の意見を相手に理解してもらうには、相手の視点で考えて、 相手にとってわかりやすい言葉で表現して伝える必要がある、ということです。

自分では、いろいろ考えた末に出した結論でしたが、結局、 自分の立場で見て思ったことを、一方的に伝えているだけでした。

いままでは、相手との考え方に大きな相違がなかったため、 なんとか相手には伝わって、事なきを得ていたのだと思います。

ですが、今回は、その相違に気づいていたにもかかわらず、 今までと同じやりかたで自分の考えを丸投げしてしまい、 まったく話がかみ合わないという状態に陥ってしまいました。

まあ、今でも、相手の立場を想定して言い直すことができていないので、 口では上記のように簡単に言っていますが、実践するのはかなり難しいと感じています。

 

…いや、でも、もう42歳ですから、 そろそろ「難しい」で済ませていてはダメなお年頃かな、と思っております。むぅ…。

 

今回も、ここまで読んでいただき、たいへんありがとうございました。
次回は、8月5日(日) の未明にお会いしましょう!

 

「いますぐ実践! Linux システム管理」の解除は、以下からできます。
http://www.usupi.org/sysad/ (まぐまぐ ID:149633)

バックナンバーは、こちらにほぼ全部そろっています。
http://www.usupi.org/sysad/backno.html

「栗日記」- 好調かと思ったらまた低迷したりで…。
http://www.usupi.org/kuri/ (まぐまぐ ID:126454)
http://usupi.seesaa.net/ (栗日記ブログ)
http://usupi.org/k/ (モバイル栗日記)


[バックナンバーのトップへ] [Linux システム管理のトップへ]

トップ

バックナンバー
    [日付順] [目的別]

プロフィール

▼ リンク

独学Linux
Linuxデスクトップ環境に関する情報が満載です。 メルマガもありますよ。
Server World
CentOS 6をサーバとしたときの設定例が、これでもかというくらいたくさん載っています。 CentOS以外のディストリビューション(Fedora, Ubuntu)も充実しています。
LINUXで自宅サーバーを構築・導入(Fedora9)
Fedora9のインストールの仕方から管理方法まで、詳しく載っています。 SearchManには情報がもりだくさんです。
マロンくん.NET
〜サーバ管理者への道〜
Linuxをサーバとして使用するための、いろいろな設定方法が載っています。 マロンくんもかわいいです。 なんといっても、マロンくんという名前がいいですね!!
日経Linux
今や数少なくなってしまったLinuxの雑誌。ニュースやガイドもあります。
Linux Square − @IT
@ITが提供する、Linux の情報が満載。 載っていない設定方法はないんじゃないでしょうか。
gihyo.jp…技術評論社
Linuxに限らず様々な技術情報が満載のサイト。 SoftwareDesign誌も、 ソフトウェア技術者は必見です。
SourceForge.JP Magazine
Linux に限らず、オープンソース関連の記事が網羅されています。
ITmediaエンタープライズ:Linux Tips 一覧
Tips というより FAQ 集でしょうか。わからないことがあれば覗きましょう。
IBM developerWorks : Linux
開発者向けですが、勉強になりますよ。
Yahoo!ニュース - Linux
Yahoo!のLinuxに関するニュース一覧です。
栗日記
システム管理とかと全然関係ありませんが、毎日栗の絵を描いています。
システム管理につかれちゃったとき、癒されたいときに、ご覧ください。:-)
WEB RANKING - PC関連
ランキングに参加してみました。押してやってください。

▼ 作ってみました

Add to Google

▼ せんでん




▼ 最近読んだ本

▼ 気に入ってる本