GNU/Linux >> Znalost Linux >  >> Linux

Proč „zip“ v A For Loop funguje, když soubor existuje, ale ne, když neexistuje?

Mám adresář, který obsahuje několik podadresářů. Existuje otázka týkající se komprimování souborů, která obsahuje odpověď, kterou jsem vždy tak trochu upravil pro své potřeby.

for i in */; do zip "zips/${i%/}.zip" "$i*.csv"; done

Narážím však na bizarní problém. Pro první sadu složek, kde jsou zips/<name>.zip neexistuje, dostávám tuto chybu:

zip error: Nothing to do! (zips/2014-10.zip)
        zip warning: name not matched: 2014-11/*.csv

nicméně když jen echo příkazy zip:

for i in */; do echo zip "zips/${i%/}.zip" "$i*.csv"; done

Poté spusťte příkaz echoed (zip zips/2014-10.zip 2014-10/*.csv ), funguje dobře a složku zapíná na zip. Nejzábavnější na tom je, že následné spuštění původního příkazu bude ve skutečnosti zazipujte složky, které nefungovaly poprvé!

Chcete-li toto chování sami vyzkoušet:

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

Uvidíte, že echo vytiskne tato prohlášení:

zip zips/2016-01.zip 2016-01/*.csv
zip zips/2016-02.zip 2016-02/*.csv
zip zips/2016-03.zip 2016-03/*.csv

Skutečný příkaz zip vám však řekne:

        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%)

Ve skutečnosti se tedy v souboru zip aktualizuje soubor .csv s kde soubor zip existuje, ale ne při vytvoření souboru zip. A pokud zkopírujete jeden z příkazů zip:

$ zip zips/2016-02.zip 2016-02/*.csv
adding: 2016-02/one.csv (stored 0%)
adding: 2016-02/two.csv (stored 0%)

Poté znovu spusťte soubor zip-all-the-things:

for i in 2*/; do zip "zips/${i%/}.zip" "$i*.csv"; done

Uvidíte, že se aktualizuje pro 2016-02 a 2016-03 . Zde je můj výstup ze 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

Také to (ne)překvapivě funguje dobře:

zsh -c "$(for i in 2*/; do echo zip "zips/${i%/}.zip" "$i*.csv"; done)"

co tady dělám špatně? (Všimněte si, že používám zsh místo bash, pokud to má nějaký rozdíl)

Přijatá odpověď:

Rozšíření pomocí shellu

Uvozovky kolem "$i*.csv" dělat rozdíl. Pomocí uvozovek shell tento řetězec rozšíří na „2014-11/*.csv“. Tento přesný soubor neexistuje a zip hlásí chybu. Bez uvozovek, * také expanduje (prostřednictvím expanze názvu/”globbing”) a výsledného zip příkaz je úplný seznam odpovídajících souborů, každý jako samostatný argument. Druhé chování můžete získat uvnitř for smyčka s:

for i in */ ; do zip "zips/${i%/}.zip" "$i"*.csv ; done

Rozšíření pomocí zip

zip může také rozšířit zástupné znaky pro sebe, ale ne ve všech situacích. Z příručky zip:

zip program může provést stejnou shodu se jmény, která jsou v zip archivu, který se upravuje nebo v případě -x (vyloučit) nebo -i (zahrnout) možnosti v seznamu souborů, se kterými se má pracovat, pomocí zpětných lomítek nebo uvozovek, aby shell neprováděl rozšíření názvu.

Původní příkaz funguje na další pokusy poté, co jste úspěšně vytvořili archiv, protože zip se pokusí porovnat zástupné znaky s obsahem existujícího archivu. Existují tam a stále existují v souborovém systému, takže jsou hlášeny pomocí updating: .

Chcete-li získat zip pro zpracování zástupných znaků při vytváření archivu, použijte -r (recurse) možnost rekurze do požadovaného adresáře a -i (zahrnout), chcete-li jej omezit na soubory odpovídající vzoru:

 for i in */ ; do zip -r "zips/${i%/}.zip" "$i" -i '*.csv' ; done

Linux
  1. Proč regulární výraz funguje v X, ale ne v Y?

  2. Proč skript Bash nerozpozná aliasy?

  3. Proč nefunguje ~/.bash_profile?

  1. Proč substituce procesu Bash nefunguje s některými příkazy?

  2. Ponechá příkaz Shuf File> File prázdný soubor, ale podobné příkazy ne?

  3. Proč překladový soubor Bash neobsahuje všechny chybové texty?

  1. Linux – Proč Setuid nefunguje?

  2. Proč Ls -l neukazuje čas a rok pro každý soubor?

  3. Proč nefunguje automatické dokončování při zadávání názvu příkazu za „zdroj“?