shellスクリプトをつかってみる
菊池です
つい最近、本番のサーバとステージングの環境でファイルやディレクトリの権限の差異が発生して
差分を調査しなければならないことがありました。
サーバが1つや2つなら,treeコマンドやlsコマンドで出力したものを印刷でもして見比べればいいのですが
今回は10台以上のサーバの差分を出さなければならなかったので
スクリプトを書こうと思いました
今までであれば簡単なスクリプトでもpythonやrubyを使って書いていたのですが
今回はshellスクリプトに挑戦してみました。
ls?tree?find?
まずはじめにファイルのアクセス権とオーナーと言った情報とファイルやディレクトリの一覧を取得することになります
ファイルの一覧といえばまっさきに思いつくのはlsやtreeコマンドでした
どちらもオプションをつけることで再帰的に末端のファイルまで必要な情報とともに出力してくれます
しかし、treeコマンドの場合
tree -f │ └── ./workspace/drinqApp/drinq/settings.gradle ├── ./workspace/ex │ ├── ./workspace/ex/Elixir.Fib.beam │ ├── ./workspace/ex/chanel_sample │ │ ├── ./workspace/ex/chanel_sample/README.md │ │ ├── ./workspace/ex/chanel_sample/_build │ │ │ └── ./workspace/ex/chanel_sample/_build/dev │ │ │ ├── ./workspace/ex/chanel_sample/_build/dev/consolidated │ │ │ │ ├── ./workspace/ex/chanel_sample/_build/dev/consolidated/Elixir.Collectable.beam │ │ │ │ ├── ./workspace/ex/chanel_sample/_build/dev/consolidated/Elixir.DBConnection.Query.beam │ │ │ │ ├── ./workspace/ex/chanel_sample/_build/dev/consolidated/Elixir.Ecto.DataType.beam │ │ │ │ ├── ./workspace/ex/chanel_sample/_build/dev/consolidated/Elixir.Ecto.Queryable.beam │ │ │ │ ├── ./workspace/ex/chanel_sample/_build/dev/consolidated/Elixir.Enumerable.beam │ │ │ │ ├── ./workspace/ex/chanel_sample/_build/dev/consolidated/Elixir.IEx.Info.beam │ │ │ │ ├── ./workspace/ex/chanel_sample/_build/dev/consolidated/Elixir.Inspect.beam │ │ │ │ ├── ./workspace/ex/chanel_sample/_build/dev/consolidated/Elixir.List.Chars.beam │ │ │ │ ├── ./workspace/ex/chanel_sample/_build/dev/consolidated/Elixir.Phoenix.HTML.FormData.beam │ │ │ │ ├── ./workspace/ex/chanel_sample/_build/dev/consolidated/Elixir.Phoenix.HTML.Safe.beam │ │ │ │ ├── ./workspace/ex/chanel_sample/_build/dev/consolidated/Elixir.Phoenix.Param.beam │ │ │ │ ├── ./workspace/ex/chanel_sample/_build/dev/consolidated/Elixir.Plug.Exception.beam │ │ │ │ ├── ./workspace/ex/chanel_sample/_build/dev/consolidated/Elixir.Poison.Decoder.beam
出力に出てくるラインが邪魔で加工しにくいです。軽くディレクトリの構造などを見渡すにはいいのですが今回はボツです! ><
次にlsですが
ls -Rl ... ./workspace/ex/hello/_build/dev/lib/gettext/ebin: 合計 260 -rw-rw-r-- 1 yakipote yakipote 1860 11月 6 02:17 Elixir.Gettext.Application.beam -rw-rw-r-- 1 yakipote yakipote 10148 11月 6 02:17 Elixir.Gettext.Backend.beam -rw-rw-r-- 1 yakipote yakipote 15724 11月 6 02:17 Elixir.Gettext.Compiler.beam -rw-rw-r-- 1 yakipote yakipote 2256 11月 6 02:17 Elixir.Gettext.Error.beam -rw-rw-r-- 1 yakipote yakipote 16452 11月 6 02:17 Elixir.Gettext.Extractor.beam -rw-rw-r-- 1 yakipote yakipote 6056 11月 6 02:17 Elixir.Gettext.ExtractorAgent.beam -rw-rw-r-- 1 yakipote yakipote 5520 11月 6 02:17 Elixir.Gettext.Fuzzy.beam -rw-rw-r-- 1 yakipote yakipote 6328 11月 6 02:17 Elixir.Gettext.Interpolation.beam -rw-rw-r-- 1 yakipote yakipote 12236 11月 6 02:17 Elixir.Gettext.Merger.beam -rw-rw-r-- 1 yakipote yakipote 2976 11月 6 02:17 Elixir.Gettext.MissingBindingsError.beam -rw-rw-r-- 1 yakipote yakipote 9728 ^C
なかなかいい感じなのですが、今回、同じファイル名で二箇所にあったり違う場所にあったりするので
ファイル名はフルパスでほしいので・・lsも今回はボツです
次にfind
find ./ -ls 7209655 8 -rw-rw-r-- 1 yakipote yakipote 4647 10月 9 11:40 ./.gvm/archive/go/src/debug/dwarf/type_test.go 7209638 4 drwxrwxr-x 2 yakipote yakipote 4096 10月 9 11:40 ./.gvm/archive/go/src/debug/dwarf/testdata 7209649 12 -rw-rw-r-- 1 yakipote yakipote 9509 10月 9 11:40 ./.gvm/archive/go/src/debug/dwarf/testdata/split.elf 7209650 4 -rw-rw-r-- 1 yakipote yakipote 2083 10月 9 11:40 ./.gvm/archive/go/src/debug/dwarf/testdata/typedef.c 7209647 12 -rwxrwxr-x 1 yakipote yakipote 10348 10月 9 11:40 ./.gvm/archive/go/src/debug/dwarf/testdata/ranges.elf 7209639 4 -rw-rw-r-- 1 yakipote yakipote 103 10月 9 11:40 ./.gvm/archive/go/src/debug/dwarf/testdata/cycle.c 7209645 4 -rw-rw-r-- 1 yakipote yakipote 54 10月 9 11:40 ./.gvm/archive/go/src/debug/dwarf/testdata/line2.c 7209642 12 -rw-rw-r-- 1 yakipote yakipote 10113 10月 9 11:40 ./.gvm/archive/go/src/debug/dwarf/testdata/line-gcc.elf 7209644 4 -rw-rw-r-- 1 yakipote yakipote 83 10月 9 11:40 ./.gvm/archive/go/src/debug/dwarf/testdata/line1.h。 7209646 4 -rw-rw-r-- 1 yakipote yakipote 415 10月 9 11:40 ./.gvm/archive/go/src/debug/dwarf/testdata/ranges.c 7209640 4 -rw-rw-r-- 1 yakipote yakipote 2624 10月 9 11:40 ./.gvm/archive/go/src/debug/dwarf/testdata/cycle.elf 7209641 12 -rw-rw-r-- 1 yakipote yakipote 10271 10月 9 11:40 ./.gvm/archive/go/src/debug/dwarf/testdata/line-clang.elf 7209648 4 -rw-rw-r-- 1 yakipote yakipote 59 10月 9 11:40 ./.gvm/archive/go/src/debug/dwarf/testdata/split.c 7209643 4 -rw-rw-r-- 1 yakipote yakipote 61 10月 9 11:40 ./.gvm/archive/go/src/debug/dwarf/testdata/line1.c 7209652 12 -rw-rw-r-- 1 yakipote yakipote 9496 10月 9 11:40 ./.gvm/archive/go/src/debug/dwarf/testdata/typedef.elf
おお、まさに欲しかった結果だ
findコマンドは探し者をするときに使うものだと思っていたのですが今回のような場合にも有用みたいです。
ファイル名が一致するものを並べて表示する
同じ場所にある同じ名前のファイルとディレクトリを比べたいのですが・・
そこで、joinです。
sqlのjoinと同じような動作をするコマンドです
キーにするフィールドを指定して、一致するものを並べて表示します
今回はファイル名にあたるフィールドをキーにしてjoinしました
こうすることでアクセス権と所有者の違いを簡単に比べることができます。
さあ書くぞ
方針
- サーバの情報をfindでとる
- ソートする
- awkでほしいフィールドだけ出力する
- 比べたいサーバでも1,2,3をおこなう
- joinでいい感じにする
どんっ!
join -1 4 -2 4 \ <(sshpass -p [password] ssh [username]@$1 find /data -ls \ | awk '{print $3" "$5" "$6" "$11;}' |sort -k4) \ <(sshpass -p [password] ssh [username]@$2 find /data -ls \ | awk '{print $3" "$5" "$6" "$11;}' | sort -k4) | grep -v total \ | grep -v : |awk 'NF' > hoge
糞読みにくいですけど、許してください
shellスクリプトの基礎がわかってないので、動くようになるまで大変でした
あとは・・並んで出力されたものを見比べて・・・
いやいやもちろん目視で確認なんかしませんよ!
違う箇所だけ出力します
cat hoge | while read line do str1=`echo $line | awk '{print $2" "$3" "$4}'` str2=`echo $line | awk '{print $5" "$6" "$7}'` if [ "$str1" = "$str2" ]; then : else echo -e ${line} fi done
よかったよかった