Saya memiliki direktori yang berisi beberapa sub-direktori. Ada pertanyaan tentang zip file yang berisi jawaban yang saya modifikasi sedikit untuk kebutuhan saya.
for i in */; do zip "zips/${i%/}.zip" "$i*.csv"; done
Namun, saya mengalami masalah yang aneh. Untuk kumpulan folder pertama, di mana zips/<name>.zip
tidak ada, saya mendapatkan kesalahan ini:
zip error: Nothing to do! (zips/2014-10.zip)
zip warning: name not matched: 2014-11/*.csv
namun ketika saya hanya echo
pernyataan zip:
for i in */; do echo zip "zips/${i%/}.zip" "$i*.csv"; done
Kemudian jalankan perintah echoed (zip zips/2014-10.zip 2014-10/*.csv
), ini berfungsi dengan baik dan membuka ritsleting folder. Kemudian bagian yang menyenangkan tentang itu adalah menjalankan perintah asli berikutnya akan sebenarnya zip folder yang tidak berfungsi pertama kali!
Untuk menguji sendiri perilaku ini:
cd /tmp
mkdir -p 2016-01 2016-02 2016-03 zips
for i in 2*/; do touch "$i"/one.csv; done
for i in 2*/; do touch "$i"/two.csv; done
zip zips/2016-03.zip 2016-03/*.csv
for i in 2*/; do echo zip "zips/${i%/}.zip" "$i*.csv"; done
for i in 2*/; do zip "zips/${i%/}.zip" "$i*.csv"; done
Anda akan melihat bahwa gema mencetak pernyataan berikut:
zip zips/2016-01.zip 2016-01/*.csv
zip zips/2016-02.zip 2016-02/*.csv
zip zips/2016-03.zip 2016-03/*.csv
Namun, perintah zip yang sebenarnya akan memberi tahu Anda:
zip warning: name not matched: 2016-01/*.csv
zip error: Nothing to do! (zips/2016-01.zip)
zip warning: name not matched: 2016-02/*.csv
zip error: Nothing to do! (zips/2016-02.zip)
updating: 2016-03/one.csv (stored 0%)
updating: 2016-03/two.csv (stored 0%)
Jadi sebenarnya memperbarui file zip dengan .csv
s tempat file zip ada, tetapi tidak saat file zip dibuat. Dan jika Anda menyalin salah satu perintah zip:
$ zip zips/2016-02.zip 2016-02/*.csv
adding: 2016-02/one.csv (stored 0%)
adding: 2016-02/two.csv (stored 0%)
Kemudian jalankan kembali zip-all-the-things:
for i in 2*/; do zip "zips/${i%/}.zip" "$i*.csv"; done
Anda akan melihatnya diperbarui untuk 2016-02
dan 2016-03
. Inilah hasil tree
saya :
.
├── 2016-01
│ ├── one.csv
│ └── two.csv
├── 2016-02
│ ├── one.csv
│ └── two.csv
├── 2016-03
│ ├── one.csv
│ └── two.csv
└── zips
├── 2016-02.zip
└── 2016-03.zip
Juga, (tidak) mengejutkan, ini berfungsi dengan baik:
zsh -c "$(for i in 2*/; do echo zip "zips/${i%/}.zip" "$i*.csv"; done)"
Apa yang saya lakukan salah di sini? (perhatikan, saya menggunakan zsh alih-alih bash, jika ada bedanya)
Jawaban yang Diterima:
Ekspansi oleh shell
Kutipan di sekitar "$i*.csv"
membuat perbedaan. Dengan tanda kutip, shell memperluas string itu ke "2014-11/*.csv". File persis itu tidak ada, dan zip
melaporkan kesalahan. Tanpa tanda kutip, *
juga meluas (melalui ekspansi nama file/”globbing”), dan zip
. yang dihasilkan perintah adalah daftar lengkap file yang cocok, masing-masing sebagai argumen terpisah. Anda bisa mendapatkan perilaku kedua, di dalam for
lingkaran, dengan:
for i in */ ; do zip "zips/${i%/}.zip" "$i"*.csv ; done
Perluasan dengan zip
zip
juga dapat memperluas wildcard untuk dirinya sendiri, tetapi tidak dalam semua situasi. Dari manual zip:
zip program dapat melakukan pencocokan yang sama pada nama yang ada di zip arsip sedang dimodifikasi atau, dalam kasus -x (kecualikan) atau -i (termasuk) opsi, pada daftar file yang akan dioperasikan, dengan menggunakan garis miring terbalik atau tanda kutip untuk memberi tahu shell agar tidak melakukan ekspansi nama.
Perintah asli berfungsi pada upaya berikutnya, setelah Anda berhasil membuat arsip, karena zip
mencoba mencocokkan karakter pengganti dengan konten arsip yang ada. Mereka ada di sana, dan masih ada di sistem file, jadi mereka dilaporkan dengan updating:
.
Untuk mendapatkan zip
untuk menangani wildcard saat membuat arsip, gunakan -r
(recurse) opsi untuk mengulang ke direktori yang diminta, dan -i
(termasuk) untuk membatasinya pada file yang cocok dengan pola:
for i in */ ; do zip -r "zips/${i%/}.zip" "$i" -i '*.csv' ; done