Por que o caractere curinga * é tão diferente entre os comandos zip e rm?

58

Eu montei um script para fazer algumas operações de arquivo para mim. Estou usando o operador curinga *para aplicar funções a todos os arquivos de um tipo, mas há uma coisa que não entendo. Eu posso unziptodos os arquivos em uma pasta como esta

unzip "*".zip

No entanto, para remover todos os arquivos zip depois, preciso fazer

rm *.zip

Ou seja, ele não deseja aspas. O descompactação, por outro lado, não funciona se eu apenas der o * (me avisa que "os arquivos não foram correspondidos").

Por que isso é diferente? Para mim, isso parece exatamente a mesma operação. Ou estou usando o curinga incorretamente?

Introduções para o wild card em Unix realmente não ir para este, e eu não conseguia localizar qualquer coisa no rmou zipdocs.

Estou usando o terminal em um Mac (Yosemite).

patrick
fonte
4
Eu não tinha idéia que unzippoderia fazer isso sem o for f in *.zip;do...doneloop de shell normal . Uma interface de usuário de linha de comando estranha e não unix.
Peter Cordes
@ Peter Acho que você não entendeu a situação. unzipaplica a glob ao conteúdo de um arquivo; você não pode obtê-los do bash com um curinga. (Você precisa de `` `for f in unzip -l archive.zip; fazer ... done`)
alexis
@alexis: Eu sabia sobre unzipaceitar globs para combinar dentro de um único arquivo zip. Mas isso é diferente; Na verdade, eu tentei unzip '*.zip'em um diretório com vários arquivos zip e extrai todos os arquivos de todos os zips. Como eu disse, super estranho. tarnão possui nenhum modo de operação como esse.
Peter Cordes
1
@ Peter vejo ... sim, isso é estranho, especialmente porque descompactar não aceitará vários argumentos de linha de comando! Claramente uma implementação somente para Windows. Interpretei mal a descrição da tarefa do OP.
alexis 23/05
1
@alexis: o PKZip é anterior ao Windows . É um programa de linha de comando do DOS, lançado pela primeira vez em 1989. A porta Unix usa basicamente o mesmo código de análise de cmdline, AFAIK.
Peter Cordes 23/05

Respostas:

68

Você explicou a situação muito bem. A peça final do quebra-cabeça é que unzippode lidar com curingas:

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

ARGUMENTOS

arquivo [.zip]

...

As expressões curinga são semelhantes às suportadas nos shells Unix usados ​​com frequência (sh, ksh, csh) e podem conter:

* corresponde a uma sequência de 0 ou mais caracteres

Ao citar o curinga *, você impediu que seu shell o expandisse, para que ele unzipveja o curinga e lide com a expansão de acordo com sua própria lógica.

rm, por outro lado, não suporta curingas por si só , portanto, tentar citar um curinga instruirá rma procurar um asterisco literal no nome do arquivo.

O motivo que unzip *.zipnão funciona é que unzipa sintaxe simplesmente não permite vários arquivos zip; se houver vários parâmetros, espera que o segundo e os seguintes sejam arquivos no arquivo morto:

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

Jeff Schaller
fonte
6
obrigado, isso faz sentido! se eu entendi corretamente, em um caso estou falando unzipo próprio idioma, no outro caso o jargão geral do unix?
patrick
6
Corrigir. É importante ter em mente o que seu shell faz versus o que um programa faz.
Jeff Schaller
7
O pkzip teve origem no DOS, que não expandiu os curingas passados ​​para os programas.
Thorbjørn Ravn Andersen
11
@patrick A maneira unix de processar vários arquivos com um programa que só pode funcionar com um arquivo por vez é usar um loop. por exemplo for f in *.zip ; do unzip -v "$f" ; done. e uma grande parte da razão pela qual o shell faz a expansão do nome do arquivo etc é algo que não é necessário para cada programa individual (o que resultaria em muitas implementações de expansão de curinga escritas independentemente, que diferiam de maneiras pequenas, mas irritantes) .
cas
25

A diferença entre esses dois comandos é o *caractere citado . Se você chamar um comando em um shell e usar o *caractere para um argumento, o próprio shell avaliará o argumento. Veja este exemplo:

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

Agora com um *:

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

O shell avalia o curinga e cria um comando da seguinte maneira:

$ ls file1.zip  file2.zip  file3.zip

Com um curinga entre aspas, ele é interpretado como um arquivo chamado (literalmente) *.zip:

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

O unziputilitário não pode ser chamado com vários arquivos compactados como argumentos. Mas, o desenvolvedor escolheu outro caminho para isso. Na página de manual:

arquivo [.zip]

[...] Expressões curinga são semelhantes às suportadas em shells Unix comumente usados ​​(sh, ksh, csh) [...] ( Certifique-se de citar qualquer caractere que possa ser interpretado ou modificado pelo sistema operacional , particularmente em Unix e VMS.)

caos
fonte
Você sabe por que os autores unzipescolheram seguir esse caminho, em vez de permitir vários arquivos compactados como argumentos?
David Etler 22/16
@DavidEtler Eu também não sei.
caos
1
Também não sei dizer por que @DavidEtler, mas, como construído, a sintaxe de descompactação aceita nomes de arquivos após o arquivo zip que se supõe ser o conteúdo desse arquivo zip. Seria ambíguo se você quisesse que um segundo arquivo zip fosse um parâmetro "descompacte-me" ou um "descompacte este arquivo zip interno do arquivo anterior".
Jeff Schaller
O @DavidEtler não sabe o que os desenvolvedores estavam pensando, mas tudo era muito mais lento e menor naquela época. Você normalmente não estava lidando com mais de um arquivo zip por vez. Você tinha disquetes com capacidade de 90 ou 250kB e estava realmente feliz por ter uma unidade de disco de 10 MB. As coisas foram comprimidas porque precisavam ser, não apenas para o transporte entre sistemas.
Joe
7

A diferença é que, no primeiro caso, o próprio shell expande o globo:

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

enquanto no segundo caso, o próprio aplicativo Does Something ™ com esse caractere literal:

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

Se não estiver entre aspas, o shell primeiro expande a glob e o comando será executado com qualquer que seja a expansão da glob shell.

agitar
fonte
2

Um comando receberá os argumentos após serem processados ​​pelo shell.

No primeiro processamento, um não citado *será expandido pelo shell (para a lista de arquivos no diretório atual (pwd) que correspondem ao padrão):

echo *.zip

Irá listar todos os .ziparquivos. Mas nãoecho "*".zip" vai .

No primeiro processamento, uma citação "*"não será expandida, será dada ao comando descompactar como parâmetro (após a remoção da citação). O comando descompactar receberá um parâmetro de *.zip:

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

É o comando descompactar que expande *para a lista de arquivos.


Também é interessante que esses dois comandos não executem exatamente a mesma ação final e quem expanda as *alterações:

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

O primeiro comando recebe um *.zipque se expande para processar todos os arquivos. O segundo comando unzipreceberá uma lista de todos os .ziparquivos no pwd, que não serão processados, pois o desenvolvedor de descompactar optou por rejeitar a expansão de mais de um ziparquivo.


fonte
0

As aspas são necessárias devido à maneira como o zip lida com vários argumentos:

rm: remova todos os arquivos na lista de argumentos

zip: descompacte o arquivo no primeiro argumento. extraia apenas os arquivos nos argumentos restantes.

$ 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

como você pode ver, ele tenta encontrar file2.zip e file3.zip dentro de file1.zip

para permitir que você extraia vários arquivos zip de uma só vez, o zip suporta a interpretação do glob por si só, com um resultado diferente.

eMBee
fonte