¿Por qué el carácter comodín * es tan diferente entre los comandos zip y rm?

58

Arme un script para hacer algunas operaciones de archivo por mí. Estoy usando el operador comodín *para aplicar funciones a todos los archivos de un tipo, pero hay una cosa que no entiendo. Puedo unziptodos los archivos en una carpeta como esta

unzip "*".zip

Sin embargo, para eliminar todos los archivos zip después, necesito hacer

rm *.zip

Es decir, no quiere las comillas. El descomprimir, por otro lado, no funciona si solo le doy el * (me da una advertencia de que "los archivos no coinciden").

¿Por qué es esto diferente? Para mí, esto parece exactamente la misma operación. ¿O estoy usando el comodín incorrectamente?

Las introducciones al comodín en Unix realmente no entran en esto, y no pude encontrar nada en los documentos rmo zip.

Estoy usando la terminal en una Mac (Yosemite).

Patricio
fuente
44
No tenía idea de que unzippodría hacer esto sin el for f in *.zip;do...donebucle de shell normal . Una interfaz de usuario de línea de comandos no similar a Unix tan extraña.
Peter Cordes
@Peter Creo que malinterpretas la situación. unzipaplica el glob al contenido de un archivo; no puedes obtenerlos de bash con un comodín. (Necesitarías `` para f in unzip -l archive.zip; do ... done`)
alexis
@alexis: sabía sobre unzipaceptar globos para que coincidan dentro de un único archivo zip. Pero esto es diferente; Realmente intenté unzip '*.zip'en un directorio con múltiples archivos zip, y extrae todos los archivos de todos los zip. Como dije, súper raro. tarno tiene ningún modo de operación como ese.
Peter Cordes
1
@Peter Ya veo ... sí, eso es extraño, ¡especialmente porque descomprimir no aceptará múltiples argumentos de línea de comandos! Claramente una implementación solo para Windows. Interpreté mal la descripción del OP de la tarea.
alexis
1
@alexis: PKZip es anterior a Windows . Es un programa de línea de comandos de DOS, lanzado por primera vez en 1989. El puerto Unix utiliza básicamente el mismo código de análisis de línea de cmd, AFAIK.
Peter Cordes

Respuestas:

68

Has explicado muy bien la situación. La pieza final del rompecabezas es que unzippuede manejar comodines:

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

ARGUMENTOS

archivo [.zip]

...

Las expresiones comodín son similares a las admitidas en los shells Unix de uso común (sh, ksh, csh) y pueden contener:

* coincide con una secuencia de 0 o más caracteres

Al citar el comodín *, evitó que su shell lo expandiera, por lo que unzipve el comodín y trata de expandirlo de acuerdo con su propia lógica.

rm, por el contrario, no admite comodines por sí solo , por lo que intentar citar un comodín le indicará rmque busque un asterisco literal en el nombre del archivo.

La razón por la que unzip *.zipno funciona es que unzipla sintaxis simplemente no permite múltiples archivos zip; Si hay varios parámetros, se espera que el segundo y los siguientes sean archivos en el archivo:

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

Jeff Schaller
fuente
66
gracias, eso tiene sentido! si entiendo correctamente, en un caso estoy hablando unzipel idioma propio, en el otro caso, la jerga general de Unix?
patrick
66
Correcto. Es importante tener en cuenta lo que hace su shell frente a lo que hace un programa.
Jeff Schaller
77
pkzip se originó en DOS que no expandió los comodines pasados ​​a los programas.
Thorbjørn Ravn Andersen
11
@patrick la forma unix de procesar múltiples archivos con un programa que solo puede funcionar con un archivo a la vez es usar un bucle. por ej for f in *.zip ; do unzip -v "$f" ; done. y una gran parte de la razón por la cual el shell hace la expansión del nombre de archivo, etc., es en sí misma que cada programa individual no tiene que hacerlo (lo que resultaría en tener muchas implementaciones de expansión de comodines escritas independientemente que diferían en formas pequeñas pero molestas) .
cas
25

La diferencia entre esos dos comandos es el *carácter entre comillas . Si llama a un comando en un shell y usa el *carácter para un argumento, el shell evaluará el argumento. Ver este ejemplo:

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

Ahora con un *:

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

El shell evalúa el comodín y crea un comando de la siguiente manera:

$ ls file1.zip  file2.zip  file3.zip

Con un comodín entre comillas, se interpreta como un archivo llamado (literalmente) *.zip:

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

La unziputilidad no puede ser llamada con múltiples archivos comprimidos como argumentos. Pero, el desarrollador eligió otra forma para esto. Desde la página del manual:

archivo [.zip]

[...] Las expresiones comodín son similares a las admitidas en los shells de Unix de uso común (sh, ksh, csh) [...] ( Asegúrese de citar cualquier carácter que de otro modo podría ser interpretado o modificado por el sistema operativo , particularmente bajo Unix y VMS.)

caos
fuente
¿Sabes por qué los autores de unzipeligieron seguir esa ruta, en lugar de permitir múltiples archivos comprimidos como argumentos?
David Etler
@DavidEtler No lo sé también.
caos
1
No puedo decir por qué tampoco, @DavidEtler, pero como está construido, la sintaxis de descomprimir acepta nombres de archivo después del archivo zip que se supone que son contenidos de ese archivo zip. Sería ambiguo si quisieras que un segundo archivo zip fuera un parámetro "descomprimirme" o un "descomprimir este archivo zip interno del archivo anterior".
Jeff Schaller
@DavidEtler no sabe lo que pensaban los desarrolladores, pero todo era mucho más lento y más pequeño en aquel entonces. Por lo general, no estaba tratando con más de un archivo zip a la vez. Tenía disquetes que contenían 90 o 250kB y estaba muy contento de tener una unidad de disco de 10MB. Las cosas estaban comprimidas porque tenían que estarlo, no solo para el transporte entre sistemas.
Joe
7

La diferencia está en el primer caso, el propio shell expande el globo:

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

mientras que en el segundo caso, la aplicación en sí hace Something ™ con ese carácter literal:

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

Si no se cita, el shell primero expande el glob, y el comando se ejecutará con lo que ese glob del shell se haya expandido.

thrig
fuente
2

Un comando recibirá los argumentos después de que el shell los haya procesado.

En el primer procesamiento, un *shell sin comillas se expandirá (a la lista de archivos en el directorio actual (pwd) que coinciden con el patrón):

echo *.zip

Listará todos los .ziparchivos. Pero no loecho "*".zip" hará .

En el primer procesamiento, una cita "*"no se expandirá, se le dará al comando descomprimir como parámetro (después de que se haya eliminado la cita). El comando descomprimir recibirá un parámetro de *.zip:

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

Es el comando descomprimir que expande el *a la lista de archivos.


También es interesante que estos dos comandos no realicen exactamente la misma acción final, y quién expande los *cambios:

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

El primer comando recibe uno *.zipque se expande para procesar todos los archivos. El segundo comando unziprecibirá una lista de todos los .ziparchivos en el pwd, que no procesará, ya que el desarrollador de descompresión ha elegido rechazar la expansión de más de un ziparchivo.


fuente
0

Las comillas son necesarias debido a la forma en que zip maneja múltiples argumentos:

rm: eliminar todos los archivos en la lista de argumentos

zip: descomprime el archivo en el primer argumento. solo extraiga los archivos en los 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 puede ver, intenta encontrar file2.zip y file3.zip dentro de file1.zip

Con el fin de permitirle extraer múltiples archivos zip a la vez, zip admite la interpretación del globo por sí mismo, con un resultado diferente.

eMBee
fuente