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

53

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 unzip todos os arquivos em uma pasta como esta

unzip "*".zip

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

rm *.zip

Ou seja, não deseja as aspas. O descompactar, por outro lado, não funciona se eu der o * (me avisa que "arquivos não foram correspondidos").

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

As apresentações do curinga no Unix não entram nessa, e eu não consegui localizar nada no rm ou zip docs.

Estou usando o terminal em um Mac (Yosemite).

    
por patrick 21.05.2016 / 16:49

5 respostas

62

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

link

ARGUMENTS

file[.zip]

...

Wildcard expressions are similar to those supported in commonly used Unix shells (sh, ksh, csh) and may contain:

* matches a sequence of 0 or more characters

Ao citar o caractere curinga *, você impediu que o shell fosse expandido, para que unzip veja o caractere curinga e lide com a expansão dele de acordo com sua própria lógica.

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

O motivo pelo qual unzip *.zip não funciona é que a sintaxe do unzip simplesmente não permite vários arquivos zip; se houver vários parâmetros, ele espera que o segundo e os subsequentes sejam arquivos no archive:

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

    
por 21.05.2016 / 17:13
23

A diferença entre esses dois comandos é o caractere * entre aspas. 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 forma:

$ ls file1.zip  file2.zip  file3.zip

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

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

O utilitário unzip não pode ser chamado com vários arquivos compactados como argumentos. Mas o desenvolvedor escolheu outro caminho para isso. A partir do manpage:

file[.zip]

[...] Wildcard expressions are similar to those supported in commonly used Unix shells (sh, ksh, csh) [...] (Be sure to quote any character that might otherwise be interpreted or modified by the operating system, particularly under Unix and VMS.)

    
por 21.05.2016 / 17:19
6

A diferença está no primeiro caso em que o próprio shell expande o glob:

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

enquanto no segundo caso o próprio aplicativo faz algo com esse caractere literal:

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

Se não for citada, o shell expandirá primeiro o glob, e o comando será executado com qualquer que seja o shell glob expandido.

    
por 21.05.2016 / 17:14
2

Um comando receberá os argumentos depois de terem sido processados pelo shell.

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

echo *.zip

Listará todos os arquivos .zip . Mas echo "*".zip" não não .

No primeiro processamento, um "*" entre aspas não será expandido, ele será dado ao comando unzip como um parâmetro (após a remoção da cotação). O comando unzip receberá um parâmetro de *.zip :

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

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

Também é interessante que esses dois comandos não executem exatamente a mesma ação final e que expandam as * changes:

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

O primeiro comando recebe um *.zip que é expandido para processar todos os arquivos. O segundo comando unzip receberá uma lista de todos os arquivos .zip no pwd, que ele não processará, já que o desenvolvedor unzip escolheu rejeitar a expansão de mais de um arquivo zip .

    
por 21.05.2016 / 22:28
0

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

rm : remova todos os arquivos da 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.

    
por 23.05.2016 / 11:57