unix linux – Pipe globs a ls

Pregunta:

Contenido del archivo de filelist :

/some/path/*.txt
/other/path/*.dat
/third/path/example.doc

Quiero enumerar esos archivos, así que hago:

cat filelist | xargs ls

Pero en lugar de expandir esos globos, obtengo:

ls: cannot access '/some/path/*.txt': No such file or directory ls: cannot access '/other/path/*.dat': No such file or directory /third/path/example.doc

Respuesta:

Las cáscaras expanden globos. Aquí, ese es uno de los casos muy raros en los que el operador implícito split + glob invocado en la sustitución de comandos sin comillas en shells similares a Bourne que no sean zsh puede ser útil:

IFS='
' # split on newline only
set +o noglob # make sure globbing is not disabled
ls -ld -- $(cat filelist) # split+glob

En zsh , harías:

ls -ld -- ${(f)~"$(<filelist)"}

Donde f es el indicador de expansión de parámetros para dividir en los avances de línea, y ~ solicita el globbing, que de otro modo no se realiza de forma predeterminada en la expansión de parámetros ni en la sustitución de comandos.

Tenga en cuenta que si la lista de archivos coincidentes es grande, puede encontrarse con un error de lista de argumentos demasiado larga (una limitación de la llamada al sistema execve() en la mayoría de los sistemas), que xargs habría xargs otro modo. En zsh , puede usar zargs en zargs lugar:

autoload zargs
zargs --eof= -- ${(f)~"$(<filelist)"} '' ls -ld --

Donde zargs dividirá la lista y ejecutará ls varias veces para evitar el límite tanto como lo haría xargs .

O puede pasar la lista a un comando que está integrado (por lo que no implica la llamada al sistema execve() ):

Para imprimir simplemente la lista de archivos:

print -rC1 -- ${(f)~"$(<filelist)"}

O para alimentarlo a xargs delimitado por NUL:

print -rNC1 -- ${(f)~"$(<filelist)"} |
  xargs -r0 ls -ld --

Tenga en cuenta que si alguno de los elementos globales no coincide con un archivo, en zsh , obtendrá un error. Si prefiere que esos globos se expandan a nada, agregaría el calificador N glob a los globos (que habilita nullglob por globo):

print -rNC1 -- ${(f)^~"$(<filelist)"}(N) |
  xargs -r0 ls -ld --

Agregar eso (N) también convertiría todas las líneas sin operadores glob en globs permitiendo filtrar archivos referenciados por ruta y que no existen; sin embargo, significaría que no puede usar calificadores glob en los globs en filelist menos que los exprese como (#q...) y habilite la opción extendedglob . También tenga en cuenta que, dado que los calificadores pueden ejecutar código arbitrario, es importante que el contenido del archivo de filelist archivos provenga de una fuente confiable.

En otros shells similares a Bourne, incluido bash , los globs que no coinciden se dejan como están, por lo que se pasarían literalmente a ls que probablemente informaría un error de que el archivo correspondiente no existe.

En bash , puede usar la opción nullglob (que copió de zsh) y manejar el caso en el que ninguno de los globs coincida especialmente:

shopt -s nullglob
IFS=$'\n'
set +o noglob
set -- $(<filelist)
(( $# == 0 )) || printf '%s\0' "$@" | xargs -r0 ls -ld --

bash , no tiene ningún equivalente para los calificadores glob de zsh . Para asegurarse de que las líneas sin operadores glob (como su /third/path/example.doc ) se traten como globs y se eliminen si no corresponden a un archivo real, puede agregar @() a las líneas (requiere extglob ) . Sin embargo, eso no funcionará para las líneas que terminan en / caracteres. Sin embargo, puede agregar @() al último carácter que no sea / y confiar en el hecho de que / siempre existe

shopt -s nullglob extglob
IFS=$'\n'
set +o noglob
set -- $(LC_ALL=C sed 's|.*[^/]|&@()|' filelist)
(( $# == 0 )) || printf '%s\0' "$@" | xargs -r0 ls -ld --

En cualquier caso, tenga en cuenta que la lista de operadores glob admitidos varía mucho con el shell. Sin embargo, el único que está usando en su muestra ( * ) debería ser compatible con todos.

Leave a Comment

Your email address will not be published.

Scroll to Top

istanbul avukat

-

web tasarım