Perché il carattere jolly * è così diverso tra i comandi zip e rm?


58

Ho messo insieme uno script per eseguire alcune operazioni sui file per me. Sto usando l'operatore jolly *per applicare le funzioni a tutti i file di un tipo, ma c'è una cosa che non capisco. Posso unziptutti i file in una cartella come questa

unzip "*".zip

Tuttavia, per rimuovere tutti i file zip in seguito, devo farlo

rm *.zip

Cioè, non vuole le virgolette. La decompressione, d'altra parte, non funziona se gli do solo il * (mi avvisa che "i file non sono stati abbinati").

Perché è diverso? A me sembra esattamente la stessa operazione. O sto usando il jolly in modo errato?

Le introduzioni al jolly in Unix non vanno proprio in questo, e non sono riuscito a trovare nulla nei documenti rmo zip.

Sto usando il terminale su un Mac (Yosemite).


4
Non avevo idea di unzippoterlo fare senza il normale for f in *.zip;do...doneloop shell. Un'interfaccia utente della riga di comando così bizzarra, non unix-like.
Peter Cordes,

@Peter Penso che tu abbia frainteso la situazione. unzipapplica il glob al contenuto di un archivio; non puoi ottenerli da bash con un carattere jolly. (Avresti bisogno di `` for f in unzip -l archive.zip; do ... done`)
alexis,

@alexis: sapevo di unzipaccettare globs da abbinare all'interno di un singolo file zip. Ma questo è diverso; In realtà ho provato unzip '*.zip'in una directory con più file zip ed estrae tutti i file da tutte le zip. Come ho detto, super-strano. tarnon ha alcuna modalità di funzionamento del genere.
Peter Cordes,

1
@Peter vedo ... sì, è strano, soprattutto perché decomprimere non accetterà più argomenti da riga di comando! Chiaramente un'implementazione solo per Windows. Ho interpretato erroneamente la descrizione del compito dell'OP.
alexis,

1
@alexis: PKZip precede Windows . È un programma da riga di comando DOS, rilasciato per la prima volta nel 1989. La porta Unix utilizza sostanzialmente lo stesso codice di analisi cmdline, AFAIK.
Peter Cordes,

Risposte:


68

Hai spiegato molto bene la situazione. L'ultimo pezzo del puzzle è che unzippuò gestire i caratteri jolly stessi:

http://www.info-zip.org/mans/unzip.html

ARGOMENTI

file [.zip]

...

Le espressioni jolly sono simili a quelle supportate nelle shell Unix di uso comune (sh, ksh, csh) e possono contenere:

* corrisponde a una sequenza di 0 o più caratteri

Citando il carattere jolly *, hai impedito alla shell di espanderlo, in modo tale da unzipvedere il carattere jolly e gestire l'espansione secondo la propria logica.

rm, al contrario, non supporta i caratteri jolly da soli , quindi il tentativo di citare un carattere jolly indica invece rmdi cercare un asterisco letterale nel nome file.

La ragione per cui unzip *.zipnon funziona è che unzipla sintassi semplicemente non consente più file zip; se ci sono più parametri, si aspetta che il 2o e quelli successivi siano file nell'archivio:

unzip [-Z] [-cflptTuvz [abjnoqsCDKLMUVWX $ /: ^]] file [.zip] [file (s) ...] [-x xfile (s) ...] [-d exdir]


6
grazie, ha senso! se capisco correttamente, in un caso parlo unzipla propria lingua, nell'altro caso il gergo generale unix?
patrick,

6
Corretta. È importante tenere presente ciò che fa la shell rispetto a ciò che fa un programma.
Jeff Schaller

7
pkzip è nato su DOS che non espandeva i caratteri jolly passati ai programmi.
Thorbjørn Ravn Andersen,

11
@patrick il modo unix di elaborare più file con un programma che può funzionare solo con un file alla volta è usare un ciclo. es for f in *.zip ; do unzip -v "$f" ; done. e gran parte del motivo PERCHÉ la shell esegue l'espansione del nome file, ecc., è la stessa cosa che ogni singolo programma non deve (il che comporterebbe un sacco di implementazioni di espansione con caratteri jolly scritte in modo indipendente che differivano in modi piccoli ma fastidiosi) .
Cas

25

La differenza tra questi due comandi è il *carattere tra virgolette . Se chiamate un comando in una shell e utilizzate il *carattere per un argomento, la shell stessa valuterà l'argomento. Vedi questo esempio:

$ ls
file1.zip  file2.zip  file3.zip  file4.txt

Ora con un *:

$ ls *.zip
file1.zip  file2.zip  file3.zip

La shell valuta il carattere jolly e crea un comando come segue:

$ ls file1.zip  file2.zip  file3.zip

Con un carattere jolly tra virgolette, viene interpretato come un file chiamato (letteralmente) *.zip:

$ ls "*".zip
ls: cannot access *.zip: No such file or directory

L' unziputilità non può essere chiamata con più file zippati come argomenti. Ma lo sviluppatore ha scelto un altro modo per questo. Dalla manpage:

file [.zip]

[...] Le espressioni jolly sono simili a quelle supportate nelle shell Unix comunemente usate (sh, ksh, csh) [...] ( Assicurati di citare qualsiasi carattere che potrebbe altrimenti essere interpretato o modificato dal sistema operativo , in particolare sotto Unix e VMS.)


Sai perché gli autori di hanno unzipscelto di seguire questa strada, piuttosto che consentire più file zippati come argomenti?
David Etler,

@DavidEtler Non lo so neanche io.
caos,

1
Non so nemmeno perché, @DavidEtler, ma la sintassi di decompressione di as-build accetta i nomi dei file dopo il file zip che si presume siano i contenuti di quel file zip. Sarebbe ambiguo se si intendesse che un secondo file zip fosse un parametro "decomprimimi" o un "decomprimere questo file zip interno dall'archivio precedente".
Jeff Schaller

@DavidEtler non sa cosa stessero pensando gli sviluppatori, ma allora tutto era molto più lento e più piccolo. Di solito non hai a che fare con più di un file zip alla volta. Avevi dei floppy che contenevano 90 o 250kB ed eri davvero felice di avere un disco da 10 MB. Le cose sono state compresse perché dovevano essere, non solo per il trasporto tra sistemi.
Joe,

7

La differenza è nel primo caso che la shell stessa espande il glob:

% cd /                                                       
% echo *
Applications Library Network System Users Volumes bin cores ...
% 

mentre nel secondo caso l'applicazione stessa Does Something ™ con quel carattere letterale:

% cd /
% perl -E 'chdir "/tmp" or die; say for glob($ARGV[0])' "*"
com.apple.launchd.aj4FEhYqm5
...

Se non quotato, la shell espande prima il glob e il comando verrà eseguito con qualunque cosa il shell glob si sia espanso.


2

Un comando riceverà gli argomenti dopo che sono stati elaborati dalla shell.

Alla prima elaborazione, una *shell non quotata verrà espansa dalla shell (all'elenco dei file nella directory attuale (pwd) che corrispondono al modello):

echo *.zip

Elencherà tutti i .zipfile. Ma non loecho "*".zip" farà .

Alla prima elaborazione, un preventivo "*"non verrà espanso, verrà dato al comando unzip come parametro (dopo che il preventivo è stato rimosso). Il comando unzip riceverà un parametro di *.zip:

$ echo unzip "*".zip
unzip *.zip

È il comando decomprimere che espande *l'elenco dei file.


È anche interessante che questi due comandi non eseguano esattamente la stessa azione finale e chi espande le *modifiche:

unzip "*".zip                ### the command unzip expands `*.zip`.
unzip *.zip                  ### the shell expands `*.zip`.

Il primo comando riceve un oggetto *.zipche si espande per elaborare tutti i file. Il secondo comando unzipriceverà un elenco di tutti i .zipfile nel pwd, che non elaborerà, poiché lo sviluppatore decompresso ha scelto di rifiutare l'espansione di più di un zipfile.


0

Le virgolette sono necessarie a causa del modo in cui zip gestisce più argomenti:

rm: rimuove tutti i file nell'elenco degli argomenti

zip: decomprime il file nel primo argomento. estrarre i file solo negli argomenti rimanenti.

$ ls *.zip
file1.zip  file2.zip  file3.zip
$ unzip *.zip
Archive:  file1.zip
caution: filename not matched:  file2.zip
caution: filename not matched:  file3.zip

come puoi vedere, cerca di trovare file2.zip e file3.zip all'interno di file1.zip

per consentirti di estrarre più file zip contemporaneamente, zip supporta l'interpretazione del glob da solo, con un risultato diverso.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.