¿Cómo redirigir una lista de rutas legibles por humanos a otro comando?

¿Cómo redirigir una lista de rutas legibles por humanos a otro comando?

Cuando se trabaja con la salida de comandos como locatelos 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 locateo findy pasar su entrada como parámetros a otro programa, puede aprovechar la NULsalida y entrada delimitadas que proporcionan algunas herramientas. locatey findambos tienen una opción ( locate's -0y find's -print0) que le permitirá tener una salida más amigable con la programación, que xargsestá diseñada para leer cones -0argumento:

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 $IFSpará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 locatesimplemente no es postprocesable.

La mayoría de locatelas implementaciones tienen una -0opción para generar rutas de archivo NULdelimitadas. 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 bash4.4+, eso podría ser:

readarray -td '' files < <(locate -0 '*.doc')
du -hc -- "${files[@]}"

Eso todavía deja dos problemas:

  1. Si locateno 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.
  2. Si por el contrario locateencuentra muchos archivos, puede terminar alcanzando un límite de execve()llamada al sistema y obtener unlista de argumentos demasiado largaerror.

Ambos problemas se pueden evitar haciendo:

locate -0 '*.doc' | xargs -r0 du -hc --

( -ry -0al ser extensiones no estándar de la implementación GNU de xargslike -hes una extensión no estándar de la implementación GNU de du).

Sin embargo, eso introduce un nuevo problema: xargsse ejecutará duvarias veces para evitar el execve()límite, pero eso significa que obtendrá varias totallíneas y también el uso del disco para un archivo vinculado varias veces puede terminar contándose varias veces.

Gracias a -r, duno se ejecutará si locateno encuentra ningún archivo, pero eso también significa que no obtendrá una 0 totallí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 dupuede comenzar a trabajar en ella tan pronto como locatecomience a generarse.

información relacionada