
Cuando se trabaja con la salida de comandos como locate
los que producen listas de rutas en "forma legible por humanos" (es decir, sin \
espacios delante), ¿cómo se redirige su salida a otro comando?
La salida de $ locate [something]
produce rutas con espacios, lo que inhibe que otros programas utilicen las rutas en caso de que contengan espacios. Por ejemplo, si tuviera que
$ du -h `locate *.doc`
esto producirá un error en todos los archivos y directorios que contengan espacios. (envolver las garrapatas en espacios no funciona)
Respuesta1
¿Cuál es la razón específica por la que estás usando locate
? Esto parece hacer lo que has pedido:
find . -type f -name '*doc' -exec du -h "{}" \;
Dicho esto, si tuen realidadSi desea utilizar una herramienta como locate
o find
y pasar su entrada como parámetros a otro programa, puede aprovechar la NUL
salida y entrada delimitadas que proporcionan algunas herramientas. locate
y find
ambos tienen una opción ( locate
's -0
y find
's -print0
) que le permitirá tener una salida más amigable con la programación, que xargs
está diseñada para leer cones -0
argumento:
find . -type f -name '*doc' -print0 | xargs -0 du -h
locate -0 '*doc' | xargs -0 du -h
Respuesta2
Si desea/necesita pasar la misma línea a varios comandos, algo como esto funcionaría:
#!/usr/bin/env bash
T="${IFS}" # Save off the Internal Field Separator
IFS=$'\n' # Set it to newline.
while read file_line
do
echo "--"
echo "${file_line}"
echo "--"
done <<< $(locate $1)
IFS="${T} # Set it back to the original IFS.
Es una buena idea envolvercualquiervariables que pueden tener espacios en "".
Respuesta3
Dejar las sustituciones de comandos ( $(...)
o la `...`
forma arcaica) sin comillas invoca split+glob (dividido solo en zsh) en shells tipo Bourne.
La división se realiza en caracteres del $IFS
parámetro especial que contiene espacio, tabulación y nueva línea (y NUL en zsh) de forma predeterminada, lo que explica por qué su comando no funciona para nombres de archivos que contienen caracteres de espacio.
Podrías hacerlo:
(IFS='
' # split on newline only
set -o noglob # disable glob
du -hc -- $(locate '*.doc'))
Pero eso aún fallaría si hay nombres de archivos que contienen caracteres de nueva línea. La salida de locate
simplemente no es postprocesable.
La mayoría de locate
las implementaciones tienen una -0
opción para generar rutas de archivo NUL
delimitadas. Siendo NUL el único valor de byte que no puede aparecer en una ruta de archivo, eso significa que la salida es posprocesable. Solo necesita dividir en NUL.
En zsh
:
IFS=$'\0'
du -hc -- $(locate -0 '*.doc')
O, mejor, usando un operador explícito de división en NUL:
du -hc -- ${(0)"$(locate -0 '*.doc')"}
En bash
4.4+, eso podría ser:
readarray -td '' files < <(locate -0 '*.doc')
du -hc -- "${files[@]}"
Eso todavía deja dos problemas:
- Si
locate
no encuentra ningún archivo,du -hc --
se ejecutará sin argumentos, lo que significa que le dará el uso del disco del directorio de trabajo actual. - Si por el contrario
locate
encuentra muchos archivos, puede terminar alcanzando un límite deexecve()
llamada al sistema y obtener unlista de argumentos demasiado largaerror.
Ambos problemas se pueden evitar haciendo:
locate -0 '*.doc' | xargs -r0 du -hc --
( -r
y -0
al ser extensiones no estándar de la implementación GNU de xargs
like -h
es una extensión no estándar de la implementación GNU de du
).
Sin embargo, eso introduce un nuevo problema: xargs
se ejecutará du
varias veces para evitar el execve()
límite, pero eso significa que obtendrá varias total
líneas y también el uso del disco para un archivo vinculado varias veces puede terminar contándose varias veces.
Gracias a -r
, du
no se ejecutará si locate
no encuentra ningún archivo, pero eso también significa que no obtendrá una 0 total
línea.
Con versiones recientes de GNU du
, esos problemas se pueden solucionar con:
locate -0 '*.doc' | du --files0-from=- -hc
Esta vez, la lista de archivos se pasa a través de una tubería en lugar de a través de argumentos, por lo que no hay límite de tamaño de los argumentos. Eso también significa que no es necesario asignar grandes cantidades de memoria para almacenar esa lista, y eso du
puede comenzar a trabajar en ella tan pronto como locate
comience a generarse.