• 締切済み

空白を含むディレクトリ名のあるループ処理

空白を含むディレクトリ名のあるループ処理 ディレクトリごとに圧縮してバックアップする処理を作っているのですが、 空白を含むディレクトリがあるとうまくいかないので困っています。 以下のようなスクリプトを作ってみました。 #!/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」として圧縮するにはどのようにしたらいいでしょうか。

みんなの回答

  • notnot
  • ベストアンサー率47% (4900/10358)
回答No.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にワイルドカードを書くだけの方が簡単です。

dell_OK
質問者

お礼

ありがとうございました。

  • entree
  • ベストアンサー率55% (405/735)
回答No.4

アスタを使えばスペースは展開されませんし、 さらにシェル変数をダブルクォートで括ることで展開を防げます。 #!/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文字として処理されてしまいます。 なので、手間と簡潔さを考えると上記のようにするのがよいと思います。

dell_OK
質問者

お礼

ありがとうございました。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

find を使うなら find ... -print0 |xargs -0 ... の方が安全でしょう.

dell_OK
質問者

お礼

ご回答いただきありがとうございます。 find の -print0 と xargs の -0 について調べてみました。 ヌル文字で区切る事によって、間違いが起きないようにするため、と解釈しました。 find の際には、付けるようにします。

  • notnot
  • ベストアンサー率47% (4900/10358)
回答No.2

元の形を生かすなら、 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 {}

dell_OK
質問者

お礼

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

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

古式ゆかしい方法だと find + xargs

dell_OK
質問者

お礼

ご回答いただきありがとうございます。 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 でその階層しか検索しないようにする方法があれば教えてください。