Actualización 2020 para usuarios de Linux:
Si usted tiene una versión puesta al día de fiesta (4,4-alfa o mejor), ya que es probable que hacer si se encuentra en Linux, entonces usted debe estar usando la respuesta de Benjamin W. .
Si está en Mac OS, que —la última vez que lo comprobé— todavía usa bash 3.2, o está usando un bash anterior, continúe con la siguiente sección.
Respuesta para bash 4.3 o anterior
Aquí hay una solución para obtener la salida de finduna bashmatriz:
array=()
while IFS= read -r -d $'\0'; do
array+=("$REPLY")
done < <(find . -name "${input}" -print0)
Esto es complicado porque, en general, los nombres de archivo pueden tener espacios, nuevas líneas y otros caracteres hostiles al script. La única forma de utilizar findy tener los nombres de los archivos separados de forma segura entre sí es utilizar -print0que imprima los nombres de los archivos separados con un carácter nulo. Esto no sería un gran inconveniente si las funciones readarray/ de bash admitieran mapfilecadenas separadas por nulos, pero no lo hacen. Bash's lo readhace y eso nos lleva al bucle anterior.
[Esta respuesta se escribió originalmente en 2014. Si tiene una versión reciente de bash, consulte la actualización a continuación].
Cómo funciona
La primera línea crea una matriz vacía: array=()
Cada vez que readse ejecuta la instrucción, se lee un nombre de archivo separado por nulos de la entrada estándar. La -ropción dice readque deje los caracteres de barra invertida solos. El -d $'\0'indica readque la entrada estará separada por nulos. Desde omitimos el nombre read, la cáscara pone la entrada en el nombre por defecto: REPLY.
La array+=("$REPLY")declaración agrega el nuevo nombre de archivo a la matriz array.
La línea final combina la redirección y la sustitución de comandos para proporcionar la salida finda la entrada estándar del whilebucle.
¿Por qué utilizar la sustitución de procesos?
Si no usamos la sustitución de procesos, el ciclo podría escribirse como:
array=()
find . -name "${input}" -print0 >tmpfile
while IFS= read -r -d $'\0'; do
array+=("$REPLY")
done <tmpfile
rm -f tmpfile
En lo anterior, la salida de findse almacena en un archivo temporal y ese archivo se usa como entrada estándar para el ciclo while. La idea de la sustitución de procesos es hacer innecesarios esos archivos temporales. Entonces, en lugar de que el whilebucle obtenga su stdin tmpfile, podemos hacer que obtenga su stdin <(find . -name ${input} -print0).
La sustitución de procesos es muy útil. En muchos lugares donde un comando quiere leer de un archivo, puede especificar la sustitución del proceso <(...), en lugar de un nombre de archivo. Existe una forma análoga >(...), que se puede usar en lugar de un nombre de archivo donde el comando quiere escribir en el archivo.
Al igual que las matrices, la sustitución de procesos es una característica de bash y otros shells avanzados. No forma parte del estándar POSIX.
Alternativa: lastpipe
Si lo desea, lastpipese puede utilizar en lugar de la sustitución del proceso (punta de sombrero: Caesar ):
set +m
shopt -s lastpipe
array=()
find . -name "${input}" -print0 | while IFS= read -r -d $'\0'; do array+=("$REPLY"); done; declare -p array
shopt -s lastpipele dice a bash que ejecute el último comando en la tubería en el shell actual (no en el fondo). De esta manera, los arrayrestos existen después de que se completa la canalización. Porque lastpipesolo tiene efecto si el control de trabajos está desactivado, ejecutamos set +m. (En una secuencia de comandos, a diferencia de la línea de comando, el control de trabajos está desactivado de forma predeterminada).
Notas adicionales
El siguiente comando crea una variable de shell, no una matriz de shell:
array=`find . -name "${input}"`
Si quisiera crear una matriz, necesitaría poner parens alrededor de la salida de find. Entonces, ingenuamente, uno podría:
array=(`find . -name "${input}"`)
El problema es que el shell realiza la división de palabras en los resultados de, findpor lo que no se garantiza que los elementos de la matriz sean los que desea.
Actualización 2019
A partir de la versión 4.4-alpha, bash ahora admite una -dopción para que el ciclo anterior ya no sea necesario. En su lugar, se puede utilizar:
mapfile -d $'\0' array < <(find . -name "${input}" -print0)
Para más información sobre esto, por favor ver (y upvote) La respuesta de Benjamin W. .