Bash: canaliza la salida 'find' en 'readarray'

14

Estoy tratando de buscar archivos usando findy poner esos archivos en una matriz Bash para poder hacer otras operaciones en ellos (por ejemplo, lso grepellos). Pero no puedo entender por qué readarrayno está leyendo el findresultado, ya que está conectado a él.

Digamos que tengo dos archivos en el directorio actual file1.txty file2.txt. Entonces la findsalida es la siguiente:

$ find . -name "file*"
./file1.txt
./file2.txt

Así que quiero canalizar eso en una matriz cuyos dos elementos son las cadenas "./file1.txt"y "./file2.txt"(sin comillas, obviamente).

He intentado esto, entre algunas otras cosas:

$ declare -a FILES
$ find . -name "file*" | readarray FILES
$ echo "${FILES[@]}"; echo "${#FILES[@]}"

0

Como puede ver en la echosalida, mi matriz está vacía.

Entonces, ¿qué estoy haciendo mal aquí exactamente? ¿Por qué readarrayno está leyendo findla salida como entrada estándar y colocando esas cadenas en la matriz?

villapx
fuente

Respuestas:

21

Cuando se usa una tubería, bash ejecuta los comandos en subcapas. Por lo tanto, la matriz se rellena, pero en una subshell, por lo que la shell principal no tiene acceso a ella.

Usar sustitución de proceso:

readarray FILES < <(find)

Tenga en cuenta que no funciona para archivos con líneas nuevas en sus nombres. Si ese fuera el caso, necesita una sintaxis más elaborada:

readarray -d '' < <(find -print0)
choroba
fuente
3
Para admitir nuevas líneas, esto es suficiente:readarray -d '' < <(find your_args -print0)
VasyaNovikov
6

La solución correcta es:

unset a; declare -a a
while IFS= read -r -u3 -d $'\0' file; do
    a+=( "$file" )        # or however you want to process each file
done 3< <(find /tmp -type f -print0)

Eso es similar a lo que Greg's BashFAQ 020 explica en detalle y esta respuesta cubre .

No tiene ningún problema con archivos con nombres impares (que no contienen NUL en el nombre), con espacios o líneas nuevas. Y el resultado se establece en una matriz, lo que lo hace útil para su posterior procesamiento.

Comunidad
fuente
Genial, esta es una mejor solución al problema que estaba tratando de resolver en primer lugar. +1 tan pronto como mi representante llegue a 15 :)
villapx
3

readarray también puede leer de stdin

readarray FILES <<< "$(find . -name "file*")"; echo "${#FILES[@]}"
smac89
fuente
Esto no funciona find -print0para proteger contra nombres de archivo "inesperados".
roaima