Elaborei 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. Posso unzip
todos os arquivos em uma pasta como esta
unzip "*".zip
No entanto, para remover todos os arquivos zip posteriormente, preciso fazer
rm *.zip
Ou seja, não quer as aspas. A descompactação, por outro lado, não funciona se eu apenas der * (me dá um aviso de 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?
Apresentações ao curingano Unix realmente não entramos nisso e não consegui localizar nada nos documentos rm
ou zip
.
Estou usando o terminal em um Mac (Yosemite).
Responder1
Você explicou muito bem a situação. A peça final do quebra-cabeça é que unzip
ela mesma pode lidar com curingas:
http://www.info-zip.org/mans/unzip.html
ARGUMENTOS
arquivo[.zip]
...
Expressões curinga são semelhantes àquelas suportadas em shells Unix comumente usados (sh, ksh, csh) e podem conter:
* corresponde a uma sequência de 0 ou mais caracteres
Ao citar o curinga *, você evitou que seu shell o expandisse, de modo que ele unzip
vê o curinga e trata de expandi-lo de acordo com sua própria lógica.
rm
, por outro lado, não suporta curingassozinho, portanto, tentar citar um curinga instruirá rm
a procurar um asterisco literal no nome do arquivo.
A razão pela qual unzip *.zip
isso não funciona é que unzip
a sintaxe do 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 arquivo:
descompacte [-Z] [-cflptTuvz[abjnoqsCDKLMUVWX$/:^]] arquivo[.zip] [arquivo(s) ...] [-x xarquivo(s) ...] [-d exdir]
Responder2
A diferença entre esses dois comandos é o *
caractere entre aspas. Se você chamar um comando em um shell e usar o *
caractere como 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 curinga entre aspas, ele é interpretado como um arquivo chamado (literalmente) *.zip
:
$ ls "*".zip
ls: cannot access *.zip: No such file or directory
O unzip
utilitário não pode ser chamado com vários arquivos compactados como argumentos. Mas, o desenvolvedor escolheu outra forma para isso. Na página de manual:
arquivo[.zip]
[...] As expressões curinga são semelhantes àquelas 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.)
Responder3
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 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 estiver entre aspas, o shell primeiro expande o globo, e o comando será executado com qualquer que seja o globo do shell expandido.
Responder4
As aspas são necessárias devido à maneira 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 o arquivo2.zip e o arquivo3.zip dentro do arquivo1.zip
para permitir a extração de vários arquivos zip de uma vez, o zip suporta a interpretação do glob por si só, com um resultado diferente.