Ich habe ein Verzeichnis, das mehrere Unterverzeichnisse enthält. Es gibt eine Frage zum Komprimieren der Dateien , die eine Antwort enthält, die ich ganz leicht an meine Bedürfnisse angepasst habe.
for i in */; do zip "zips/${i%/}.zip" "$i*.csv"; done
Ich stoße jedoch auf ein bizarres Problem. Bei den ersten Ordnern, zips/<name>.zip
die nicht vorhanden sind, wird folgende Fehlermeldung angezeigt:
zip error: Nothing to do! (zips/2014-10.zip)
zip warning: name not matched: 2014-11/*.csv
aber wenn ich nur echo
die zip-Anweisungen habe:
for i in */; do echo zip "zips/${i%/}.zip" "$i*.csv"; done
Führen Sie dann den Befehl echoed ( zip zips/2014-10.zip 2014-10/*.csv
) aus, er funktioniert einwandfrei und komprimiert den Ordner. Dann ist der spaßige Teil daran ist , dass nachfolgende Durchläufe des ursprünglichen Befehl wird tatsächlich Ordner Reißverschluss, der nicht das erste Mal nicht funktioniert!
So testen Sie dieses Verhalten selbst:
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
Sie werden sehen, dass das Echo diese Anweisungen druckt:
zip zips/2016-01.zip 2016-01/*.csv
zip zips/2016-02.zip 2016-02/*.csv
zip zips/2016-03.zip 2016-03/*.csv
Der eigentliche Zip-Befehl sagt Ihnen jedoch:
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%)
Es wird also tatsächlich die Zip-Datei mit dem .csv
s aktualisiert, in dem die Zip-Datei vorhanden ist, aber nicht, wenn die Zip-Datei erstellt wird. Und wenn Sie einen der Zip-Befehle kopieren:
$ zip zips/2016-02.zip 2016-02/*.csv
adding: 2016-02/one.csv (stored 0%)
adding: 2016-02/two.csv (stored 0%)
Führen Sie dann den Reißverschluss erneut aus:
for i in 2*/; do zip "zips/${i%/}.zip" "$i*.csv"; done
Sie werden sehen, dass es für 2016-02
und aktualisiert wird 2016-03
. Hier ist meine Ausgabe von tree
:
.
├── 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
Auch (un) überraschend funktioniert dies einwandfrei:
zsh -c "$(for i in 2*/; do echo zip "zips/${i%/}.zip" "$i*.csv"; done)"
Was mache ich hier falsch? (Beachten Sie, dass ich zsh anstelle von bash verwende, wenn das einen Unterschied macht.)
zip zips/2014-10.zip 2014-10/*.csv
(auch zum Q hinzugefügt)*cvs
Datei vorhanden ist und nicht fehlt.zip
. Können Sie uns ein minimales Beispiel für die von Ihnen verwendete Verzeichnis- / Dateistruktur geben, damit wir sie neu erstellen und den Fehler testen können?Antworten:
Erweiterung durch die Schale
Die Anführungszeichen
"$i*.csv"
machen den Unterschied. Mit den Anführungszeichen erweitert die Shell diese Zeichenfolge auf "2014-11 / *. CSV". Diese genaue Datei existiert nicht undzip
meldet einen Fehler. Ohne Anführungszeichen wird das*
ebenfalls erweitert (über Dateinamenerweiterung / "Globbing"), und der resultierendezip
Befehl ist eine vollständige Liste der übereinstimmenden Dateien, jeweils als separates Argument. Sie können das zweite Verhalten innerhalb derfor
Schleife erhalten mit:Erweiterung per Reißverschluss
zip
kann auch Platzhalter für sich selbst erweitern, jedoch nicht in allen Situationen. Aus dem Zip-Handbuch :Der ursprüngliche Befehl funktioniert bei nachfolgenden Versuchen, nachdem Sie erfolgreich ein Archiv erstellt haben, da
zip
versucht wird, die Platzhalter mit dem Inhalt des vorhandenen Archivs abzugleichen. Sie sind dort vorhanden und befinden sich noch im Dateisystem, sodass sie mit gemeldet werdenupdating:
.Um
zip
die Platzhalter beim Erstellen des Archivs zu verarbeiten, verwenden Sie die-r
Option (recurse), um in das angeforderte Verzeichnis zurückzukehren, und-i
(include), um es auf Dateien zu beschränken, die dem Muster entsprechen:quelle