He estado estudiando sobre la línea de comando y aprendí que |
(pipeline) está destinado a redirigir la salida de un comando a la entrada de otro. Entonces, ¿por qué el comando ls | file
no funciona?
file
input es uno de los más nombres de archivo, como file filename1 filename2
ls
La salida es una lista de directorios y archivos en una carpeta, así que pensé que ls | file
se suponía que debía mostrar el tipo de archivo de cada archivo en una carpeta.
Sin embargo, cuando lo uso, el resultado es:
Usage: file [-bcEhikLlNnprsvz0] [--apple] [--mime-encoding] [--mime-type]
[-e testname] [-F separator] [-f namefile] [-m magicfiles] file ...
file -C [-m magicfiles]
file [--help]
Como hubo algún error con el uso del file
comando
command-line
ls
pipe
file-command
IanC
fuente
fuente
ls
, indica que desea que todos los archivos en el directorio actual se manejen con elfile
comando. ... Entonces, ¿por qué no hacer simplemente:,file *
que responderá con una línea para cada archivo, carpeta.file *
es la forma más inteligente, me preguntaba por quéls
no funcionaba la salida. Duda despejada :)ls
es generalmente una mala idea.Respuestas:
El problema fundamental es que
file
espera nombres de archivo como argumentos de línea de comandos, no en stdin. Cuando escribe,ls | file
la salida dels
se pasa como entrada afile
. No como argumentos, como entrada.¿Cual es la diferencia?
Los argumentos de la línea de comandos son cuando escribe banderas y nombres de archivos después de un comando, como en
cmd arg1 arg2 arg3
. En los scripts de shell estos argumentos están disponibles como las variables$1
,$2
,$3
, etc. En C es posible acceder a ellos a través dechar **argv
yint argc
argumentos amain()
.La entrada estándar, stdin, es un flujo de datos. Algunos programas tienen gusto
cat
owc
leen de stdin cuando no se les da ningún argumento de línea de comandos. En un script de shell puede usarread
para obtener una sola línea de entrada. En C puedes usarscanf()
ogetchar()
, entre varias opciones.file
normalmente no lee de stdin. Espera que se pase al menos un nombre de archivo como argumento. Es por eso que imprime el uso cuando escribels | file
, porque no pasó una discusión.Puede usar
xargs
para convertir stdin en argumentos, como enls | xargs file
. Aún así, como menciona Terdon , analizarls
es una mala idea. La forma más directa de hacer esto es simplemente:fuente
file
a obtener nombres de archivos de su entrada, usandols | file -f -
. Sigue siendo una mala idea de c.ls
la salida enfile
el stdin. Pruébalo.file $(ls)
, que también funciona, de otra manera.Porque, como dices, la entrada de
file
tiene que ser nombres de archivo . La salida dels
, sin embargo, es solo texto. El hecho de que sea una lista de nombres de archivos no cambia el hecho de que es simplemente texto y no la ubicación de los archivos en el disco duro.Cuando ve un resultado impreso en la pantalla, lo que ve es texto. Si ese texto es un poema o una lista de nombres de archivos no hace ninguna diferencia para la computadora. Todo lo que sabe es que es texto. Esta es la razón por la que puede pasar la salida de los
ls
programas que toman el texto como entrada (aunque realmente no debería ):Entonces, para usar la salida de un comando que enumera los nombres de los archivos como texto (como
ls
ofind
) como entrada para un comando que toma nombres de archivos, debe usar algunos trucos. La herramienta típica para esto esxargs
:Sin embargo, como dije antes, realmente no quieres analizar la salida de
ls
. Algo asífind
es mejor (print0
imprime un en\0
lugar de una nueva línea después de cada nombre de archivo y el-0
dexargs
permite que se ocupe de dicha entrada; este es un truco para que sus comandos funcionen con nombres de archivo que contienen nuevas líneas):Que también tiene su propia forma de hacerlo, sin necesidad
xargs
de nada:Finalmente, también puedes usar un bucle de shell. Sin embargo, tenga en cuenta que, en la mayoría de los casos,
xargs
será mucho más rápido y más eficiente. Por ejemplo:fuente
file
no parece que realmente leer la entrada estándar a menos que reciba una explícita-
marcador de posición: compararfile foo
,echo foo | file
yecho foo | file -
; de hecho, que es probablemente la razón para el mensaje de uso en el caso de los programas operativos (es decir, que no es realmente debido a la salida dels
es "simplemente el texto", sino más bien porque la lista de argumentos quefile
está vacía)echo foo | file -
realidad no se ejecutafile
en el archivofoo
sino en la secuencia stdin.cat
eso, excepto stdin sin,-
excepto cuando se dan argumentos de archivo, creo?No "redirige" la salida, sino que toma la salida de un programa y la usa como entrada, mientras que el archivo no toma entradas sino los nombres de archivo como argumentos , que luego se prueban. Las redirecciones no pasan estos nombres de archivo como argumentos ni las tuberías , más tarde lo que está haciendo.
Lo que puede hacer es leer los nombres de archivo de un archivo con la
--files-from
opción si tiene un archivo que enumera todos los archivos que desea probar, de lo contrario, simplemente pase las rutas a sus archivos como argumentos.fuente
La respuesta aceptada explica por qué el comando de tubería no funciona de inmediato, y con el
file *
comando, ofrece una solución simple y directa.Me gustaría sugerir otra alternativa que podría ser útil en algún momento. El truco es usar el
(`)
carácter de retroceso . El backtick se explica con gran detalle aquí . En resumen, toma el resultado del comando encerrado en los backticks y lo sustituye como una cadena en el comando restante.Por lo tanto,
find `ls`
tomará la salida dells
comando y la sustituirá como argumentos para elfind
comando. Esto es más largo y más complicado que la solución aceptada, pero sus variantes pueden ser útiles en otras situaciones.fuente
command
(no puedo encontrar el código de barra diagonal inversa en mi teléfono) para expandir la salida de un comando en el bash y usarlo como parámetro para otros comandos. Realmente útil, aunque usarlo en este caso (con ls ) aún resultaría en algunos problemas debido a los caracteres especiales en algunos nombres de archivo.La salida de a
ls
través de una tubería es un bloque sólido de datos con 0x0a que separa cada línea, es decir, un carácter de salto de línea, yfile
obtiene esto como un parámetro, donde espera que varios caracteres funcionen en uno a la vez.Como regla general, nunca lo use
ls
para generar una fuente de datos para otros comandos: un día se canalizará ... ¡rm
y luego tendrá problemas!Es mejor usar un bucle, como el
for i in *; do file "$i" ; done
que producirá la salida que desea, de manera predecible. Las comillas están ahí en caso de nombres de archivo con espacios.fuente
file *
;-)ls
es una muy, muy mala idea . No solo porque puede pasarlo a algo dañino comorm
, más importante porque se rompe en cualquier nombre de archivo no estándar.rm
Toma nombres de archivos de entrada estándar? Yo creo que no. Además, como regla general,ls
ha sido uno de los principales ejemplos de una fuente de datos para el uso de tuberías de Unix desde el comienzo de Unix. Es por eso que el valor predeterminado es un simple nombre de archivo por línea sin atributos ni adornos cuando su salida es una tubería, a diferencia de su formato predeterminado habitual cuando la salida es el terminal.Si desea usar una tubería para alimentar,
file
use la opción-f
que normalmente va seguida de un nombre de archivo, pero también puede usar un solo guión-
para leer desde la entrada estándar, entoncesEl truco con el guión
-
funciona con muchas de las utilidades de línea de comandos estándar (aunque a--
veces lo es ), por lo que siempre vale la pena intentarlo.La herramienta
xarg
es mucho más poderosa y en la mayoría de los casos solo es necesaria si la lista de argumentos es demasiado larga (vea esta publicación para más detalles).fuente
--
? Nunca he visto eso.--
es típicamente el indicador de "fin de banderas".Funciona usando el comando como a continuación
Me va a funcionar mejor
fuente
Esto también debería funcionar:
como también se discute aquí: https://unix.stackexchange.com/questions/5778/whats-the-difference-between-stuff-and-stuff
fuente
$()
método es el mismo que el método de retroceso en askubuntu.com/a/795744/158442