アプリ版:「スタンプのみでお礼する」機能のリリースについて

空白を含むディレクトリ名のあるループ処理
ディレクトリごとに圧縮してバックアップする処理を作っているのですが、
空白を含むディレクトリがあるとうまくいかないので困っています。

以下のようなスクリプトを作ってみました。
#!/bin/bash
for dirname in `ls -1 /data`
do
zip -r $dirname.zip /data/$dirname/
done

ディレクトリ構造は以下のとおりです。
/data
/data/data1
/data/data2
/data/data3

この状態だと問題ありませんが、
これに次のようなディレクトリがあると、
/data/data1 copy
ディレクトリ「data1 copy」としてうまく処理してくれず、
次のようなエラーになります。
zip warning: name not matched: /data/copy/

ディレクトリ「/data/copy/」がないと言う事だと思うのですが、
その前に「data1」の処理が2回行われたメッセージが出ていました。
zip コマンドを echo $dirname に変更して実行すると、
data1
data1
copy
data2
data3
と表示されたので、
「data1 copy」が「data1」と「copy」に分断されて処理されているようです。

「data1 copy」を「data1 copy.zip」として圧縮するにはどのようにしたらいいでしょうか。

A 回答 (5件)

#2です。

訂正と補足。
find /data -mindepth 1 -maxdepth 1 -type d | xargs -i zip -r "`basename {}`".zip {}
と、basenameのところを" "で囲まないといけませんでした。

#1のお礼中で、xargsを使っていたのでそれに習いましたが、xargs -i を使わず、これでもいいです。
find /data -mindepth 1 -maxdepth 1 -type d -exec zip -r "`basename {}`".zip {} \;

また、#3の方が書いているように、空白文字(空白、タブ、改行)を含んだファイル名をfind+xargsで扱うときには、一般的には、ファイル名をヌル文字区切りにする
>find ... -print0 |xargs -0 ...
を使います。今回は、xargs で -i オプションを使っているので、たまたま必要ないだけです。


なお、IFSを空に設定しなくても、
>連続する複数ある区切り文字が1文字として処理されてしまいます
ということはないのですが、ファイル名が空白文字で始まったり終わったりしていると、IFSを空にしないでread dirnameだと、それら空白文字が落ちてしまいます。
ls を使う必然性がないなら、#4の方の回答のように、単にforにワイルドカードを書くだけの方が簡単です。
    • good
    • 0

アスタを使えばスペースは展開されませんし、


さらにシェル変数をダブルクォートで括ることで展開を防げます。

#!/bin/bash
for dirname in /data/*
do
test -d "$dirname" || continue
zip -r "$dirname".zip /data/"$dirname"/
done

あと、while read ... を使う場合は IFS を設定した上で while read -r ...
としなければ連続する複数ある区切り文字が1文字として処理されてしまいます。
なので、手間と簡潔さを考えると上記のようにするのがよいと思います。
    • good
    • 1

find を使うなら


find ... -print0 |xargs -0 ...
の方が安全でしょう.
    • good
    • 1
この回答へのお礼

ご回答いただきありがとうございます。

find の -print0 と xargs の -0 について調べてみました。
ヌル文字で区切る事によって、間違いが起きないようにするため、と解釈しました。

find の際には、付けるようにします。

お礼日時:2010/05/26 11:35

元の形を生かすなら、


ls -1 /data | while read dirname
do
zip -r "$dirname".zip /data/"$dirname"/
done

>find でその階層しか検索しないようにする方法があれば教えてください。

findを使うなら、
find /data -mindepth 1 -maxdepth 1 -type d | xargs -i zip -r `basename {}`.zip {}
    • good
    • 0
この回答へのお礼

ご回答いただきありがとうございます。

他にいただいた回答なども含めて、まだいろいろと試している最中です。

元の形でもなんとかできそうなのですね。
元の形は、よくわからないで私が作ったので、なんとも言えない形でした。
と言うのは、それぞれのサブディレクトリ名で圧縮されるのはよかったのですが、
できれば別のディレクトリに圧縮ファイルを作成したかったのです。
質問では書かなかったのですが、圧縮後に別のディレクトリに移動させるために、
mv で処理していました。
これが find と xargs なら、たぶん basename で /data のルートからのディレクトリ名を省き、
サブディレクトリ名だけにできて、別のディレクトリ名と合わせる事で、
直接そこへ圧縮ファイルを作成できるのではないかと思っています。

いろいろなやり方があるので、他にいただいた回答も試して、どうするか決めたいと思います。

お礼日時:2010/06/02 16:50

古式ゆかしい方法だと


find + xargs
    • good
    • 0
この回答へのお礼

ご回答いただきありがとうございます。

find と xargs で次のようにするとうまくいけたような気がします。
find /data/* -type d | xargs -i zip -r {}.zip {}

find と xargs の使い方を調べて、なんとかこうしたのですが、
これで問題ないでしょうか。

今は、/data/data1 以下の階層にはディレクトリがないのでいいのですが、
例えば、階層が「/data/data1/sub1」などとあった場合には、
find でそのディレクトリが検索されてしまい、
/data/data1/sub1 の処理がされる上に、
/data/data1 の処理の中にも sub1 がされてしまいます。

find でその階層しか検索しないようにする方法があれば教えてください。

お礼日時:2010/05/24 13:47

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!