Primero para cortar las respuestas triviales pero inaplicables: no puedo usar ni el truco find
+ xargs
ni sus variantes (como find
con -exec
) porque necesito usar pocas expresiones de este tipo por llamada. Volveré a esto al final.
Ahora, para un mejor ejemplo, consideremos:
$ find -L some/dir -name \*.abc | sort
some/dir/1.abc
some/dir/2.abc
some/dir/a space.abc
¿Cómo paso esos argumentos a program
?
Solo hacerlo no hace el truco
$ ./program $(find -L some/dir -name \*.abc | sort)
falla ya que program
obtiene los siguientes argumentos:
[0]: ./program
[1]: some/dir/1.abc
[2]: some/dir/2.abc
[3]: some/dir/a
[4]: space.abc
Como se puede ver, la ruta con el espacio se dividió y program
considera que son dos argumentos diferentes.
Cotizar hasta que funcione
Parece que los usuarios novatos como yo, cuando se enfrentan a tales problemas, tienden a agregar citas al azar hasta que finalmente funciona, solo que aquí no parece ayudar ...
"$(…)"
$ ./program "$(find -L some/dir -name \*.abc | sort)"
[0]: ./program
[1]: some/dir/1.abc
some/dir/2.abc
some/dir/a space.abc
Debido a que las comillas evitan la división de palabras, todos los archivos se pasan como un solo argumento.
Citando caminos individuales
Un enfoque prometedor:
$ ./program $(find -L some/dir -name \*.abc -printf '"%p"\n' | sort)
[1]: "some/dir/1.abc"
[2]: "some/dir/2.abc"
[3]: "some/dir/a
[4]: space.abc"
Las citas están ahí, claro. Pero ya no se interpretan. Son solo parte de las cuerdas. ¡Entonces no solo no impidieron la división de palabras, sino que también entraron en discusiones!
Cambiar IFS
Entonces traté de jugar con ellos IFS
. Preferiría find
con -print0
y sort
con de -z
todos modos, para que no tengan problemas en las "rutas cableadas". Entonces, ¿por qué no forzar la división de palabras en el null
personaje y tenerlo todo?
$ ./program $(IFS=$'\0' find -L some/dir -name \*.abc -print0 | sort -z)
[0]: ./program
[1]: some/dir/1.abcsome/dir/2.abcsome/dir/a
[2]: space.abc
Por lo tanto, todavía se divide en el espacio y no se divide en el null
.
Traté de colocar la IFS
tarea tanto en $(…)
(como se muestra arriba) como antes ./program
. También probé otra sintaxis como \0
, \x0
, \x00
tanto citado con '
y "
así como con y sin el $
. Ninguno de esos parecía hacer ninguna diferencia ...
Y aquí estoy sin ideas. Intenté algunas cosas más, pero todas parecían tener los mismos problemas enumerados.
¿Qué más puedo hacer? ¿Es factible en absoluto?
Claro, podría hacer que program
acepte los patrones y hacer búsquedas por sí mismo. Pero es mucho trabajo doble mientras lo arregla a una sintaxis específica. (¿Qué hay de proporcionar archivos por un grep
por ejemplo?).
También podría hacer que program
acepte un archivo con una lista de rutas. Entonces puedo volcar fácilmente la find
expresión en algún archivo temporal y proporcionar la ruta solo a ese archivo. Esto podría admitirse a lo largo de rutas directas, de modo que si el usuario solo tiene una ruta simple, se puede proporcionar sin archivo intermedio. Pero esto no parece agradable: uno necesita crear archivos adicionales y cuidarlos, sin mencionar la implementación adicional requerida. (En el lado positivo, sin embargo, podría ser un rescate para los casos en que la cantidad de archivos como argumentos comienzan a causar problemas con la longitud de la línea de comandos ...)
Al final, déjame recordarte nuevamente que los trucos find
+ xargs
(y similares) no funcionarán en mi caso. Para simplificar la descripción, solo estoy mostrando un argumento. Pero mi verdadero caso se parece más a esto:
$ ABC_FILES=$(find -L some/dir -name \*.abc | sort)
$ XYZ_FILES=$(find -L other/dir -name \*.xyz | sort)
$ ./program --abc-files $ABC_FILES --xyz-files $XYZ_FILES
Así que hacer una xargs
búsqueda de uno todavía me deja con la forma de lidiar con el otro ...
mapfile
(o su sinónimoreadarray
). ¡Pero funciona!