概要
複数のディレクトリを別々にzip化するスクリプト組んだら思いの外はまったので、備忘録的に、勉強メモ的に記録しておきます。
内容
「特定のディレクトリ」を「カレントディレクトリにある全てのディレクトリ」だとしましょう。
はじまりのスクリプト
$ find . -type d -depth 1 | xargs -I% zip -r % %
-type d
はディレクトリ指定、-depth 1
はカレントディレクトリにあるもの、という条件指定です。-depth 1
がないとカレントディレクトリ自体もヒットするので注意(もちろんカレントディレクトリを外すやり方は他にもいっぱいあると思いますが)
これでうまくいったように見えたんですが、特定のディレクトリ名で失敗していました。
その一つは、失敗する条件はよく分かってないんですが、zip
の第一引数に.zip
を省略せずに書いた場合に収まりました。
$ find . -type d -depth 1 | xargs -I% zip -r %.zip %
他にも失敗する場合があり、これは別エントリにしました。
一言で言うと、ディレクトリ名が長い時、Macのxargsの仕様上%
が展開されないので、失敗することがありました。これはMacでxargs
を使う限りどうしようもなさそう。
xargsがだめならforを使えばいいじゃない
次に、書いたのがこれ。
$ for dir in `find . -type d -depth 1`; do zip -r $dir.zip $dir; done
xargsでやっていたところをforループで置き換えてみました。が、これもうまく行きませんでした。何故ならfind . -type d -depth 1
でヒットするディレクトリ名にスペースが含まれていて、それが別々に$dir変数に入っていたからです。
空白で区切られてしまうなら、デリミタを変えればいいじゃない
さらに調べていると、$IFS
という変数でループする時のデリミタを変えられることが分かったので、$IFSをヌル文字にして、find
の出力を-print0
オプションでヌル文字区切りにしてみました。
$ IFS="\0"; for dir in `find . -type d -depth 1 -print0`; do zip -r $dir.zip $dir; done
しかしこれも成功せず、何故か0
区切りでループが回ってしまいました。謎。
あと$IFSを改行文字にして、xargs
のオプションを-print
にしてやってみたりしましたが失敗。
突如現れたread
で、さらにぐぐって調べてみるといい感じなものを見つけました。
要約すると「$IFSにヌル文字入れてみても上手くいかないんだけどどうしたらいい?」って質問対する答えにread
を使ったスクリプトが提示されています。これを参考に書いてみる。
$ find . -type d -depth 1 | while IFS= read -r dir; do zip -r $dir.zip $dir; done
ktkr!成功しました。ここに来るまで長かった。。。
よく考えたら-execでよくね
あとになって-exec
使えばよくね?って気づきました。
$ find . -type d -depth 1 -exec zip -r {}.zip {} \;
普通に動く。これが一番シンプルで良さそう。
ただ、read
を使う方が柔軟性はありそうです。