LoginSignup
10
9

More than 5 years have passed since last update.

特定のディレクトリをzip化するスクリプトを書いたときにぶつかった問題とその対処法

Posted at

概要

複数のディレクトリを別々に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を使う方が柔軟性はありそうです。

10
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
9