質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

コマンド

コマンドとは特定のタスクを行う為に、コンピュータープログラムへ提示する指示文です。多くの場合、コマンドはShellやcmdようなコマンドラインインターフェイスに対する指示文を指します。

zip

ZIPとは、複数のファイルをひとつにまとめて圧縮したり、圧縮したファイルを展開することができるアーカイブフォーマットです。 1998年以降のWindowsOS各バージョンで、標準の圧縮フォルダとして採用されています。 MacOSでも、X v10.3以降に他の圧縮ソフトとまとめてZIP機能を採用しています。

Q&A

解決済

2回答

3908閲覧

findコマンドの結果からzipファイル作成

kota005g

総合スコア1

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

コマンド

コマンドとは特定のタスクを行う為に、コンピュータープログラムへ提示する指示文です。多くの場合、コマンドはShellやcmdようなコマンドラインインターフェイスに対する指示文を指します。

zip

ZIPとは、複数のファイルをひとつにまとめて圧縮したり、圧縮したファイルを展開することができるアーカイブフォーマットです。 1998年以降のWindowsOS各バージョンで、標準の圧縮フォルダとして採用されています。 MacOSでも、X v10.3以降に他の圧縮ソフトとまとめてZIP機能を採用しています。

0グッド

1クリップ

投稿2020/04/30 11:24

編集2020/05/01 01:03

お世話になります

前提・実現したいこと

指定したディレクトリパス以下から特定条件を満たすファイルだけを
かき集めてzipファイルを作成したいです。

下記のようなファイルが存在していたとして
/home/test
├── 20200429
│   ├── 1.dat
│   ├── 2.dat
│   └── 3.txt
├── 20200430
│   └── 4.dat
└── work

/home/test/workの下に、
各日付フォルダ内の「*.dat」のファイルのみを集めて圧縮したzipファイル
・20200429.zip
├ 1.dat
└ 2.dat
・20200430.zip
└ 4.dat
を作成するのが、やりたいことです。

発生している問題・エラーメッセージ / 試したこと

端末上で実行するコマンドを考えてみましたが、下記実行結果となり、うまく行きませんでした。

# cd /home/test # find . -maxdepth 1 -mindepth 1 -type d -not -path "./work" -exec bash -c "zip -rj .work/$(basename \"{}\").zip {} -i \"*.dat\" " \; zip I/O error: No such file or directory zip error: Could not create output file (.work/./20200430.zip) zip I/O error: No such file or directory zip error: Could not create output file (.work/./20200429.zip)

確認のため、試しにzipコマンドの前に「echo」を入れて実行すると

# find . -maxdepth 1 -mindepth 1 -type d -not -path "./work" -exec bash -c "echo zip -rj .work/$(basename \"{}\").zip {} -i \"*.dat\" " \; zip -rj .work/./20200430.zip ./20200430 -i *.dat zip -rj .work/./20200429.zip ./20200429 -i *.dat

という結果でした。

質問内容

2点、質問があります。
・「$(basename "{}")」の実行結果は、「20200430」になることを期待したのですが、
「./20200430」となってしまいます。
試しに「# basename ./20200430」と打つと「20200430」の結果が得られます。
何故期待した結果と違ってしまうのでしょうか。
・コマンド最後の*.datの部分のダブルクォーテーションが消えています。
ダブルクォーテーションを維持するにはどうすれば良いでしょうか。

追記

コマンド中に誤記がありました。下記に読み替えてください。
× .work/$(basename "{}").zip
○ ./work/$(basename "{}").zip

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

こういうケースでは、xargs -I{}を使う場合が多いでしょう。

1つ目の質問。
$(basename \"{}\")basenameが実行されるのは、findから起動されたbashが実行されるときじゃなくて、findに渡されるコマンドラインを作る時点です。

つまり、
step1: $(basename \"{}\")が実行され結果の{}に置換される。
step2: find . -maxdepth 1 -mindepth 1 -type d -not -path "./work" -exec bash -c "echo zip -rj .work/{}.zip {} -i \"*.dat\" " \;が実行される。
step3: find./20200430を選び、{}を置換して、bash -c "echo zip -rj .work/\"./20200430\".zip ./20200430 -i \"*.dat\" "が起動される。
step4: echo zip -rj .work/./20200430.zip ./20200430 -i "*.dat"が実行される。
step5: zip -rj .work/./20200430.zip ./20200430 -i *.datが表示される。

です。
basenameをstep3の後で行われるようにするには、"じゃなくて'で囲みます。ついでに不要な引用符も省くと、

sh

1find . -maxdepth 1 -mindepth 1 -type d -not -path ./work -exec \ 2 bash -c 'echo zip -rj .work/$(basename {}).zip {} -i "*.dat"' \;

なお、.はカレントディレクトリを意味するので元のままでも良いです。

2つ目の質問。
それでいいです。ちゃんとワイルドカードの展開が抑止されたまま、zipに渡ります。

#追記
私ならこう書くというのは、

Bash

1for d in * 2do if [ -d "$d" -a "$d" != work ] 3 then zip -rj ".work/$d.zip" "./$d" -i "*.dat" 4 fi 5done

ところで、ZIPファイル作成場所が.workとなってますが、workの間違いでは?
とりあえず.workのまま回答していますが。

投稿2020/04/30 13:21

編集2020/04/30 14:49
otn

総合スコア84505

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kota005g

2020/05/01 01:13 編集

ご回答とご指摘ありがとうございます。 引用符について ・コマンド実行時に、真っ先に変数を値に展開したい。→ダブルクォート ・変数を展開したくない(bash -cが実行時に変数を値に展開したい)。→シングルクォート という使い分けだと理解しました。 ご指摘内容については誤記でした。本文に追記しておきます。 ご記載いただいたコードで、やりたいことが実現できました。 大変助かりました。
guest

0

ワンライナーじゃないですけど。

sh

1#!/bin/sh 2root=./ 3for p in $(find $root -type d -name '[0-9]*') 4do 5 zip -rj $p.zip $p -i '*.dat' 6done

投稿2020/04/30 12:52

編集2020/04/30 13:03
aobaoba

総合スコア63

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kota005g

2020/05/01 01:16 編集

ご回答ありがとうございます。 シンプルでわかりやすいですね。 最終的にバッチにするつもりでワンライナーにはこだわってはいなかったので、 参考にさせていただきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問