Parece que la forma canónica de hacer esto bash
es algo así como
unset args
while IFS= read -r line; do
args+=("$line")
done < file
cmd "${args[@]}"
o, si su versión de bash tiene mapfile
:
mapfile -t args < filename
cmd "${args[@]}"
La única diferencia que puedo encontrar entre el mapfile y el ciclo while-read versus el one-liner
(set -f; IFS=$'\n'; cmd $(<file))
es que el primero convertirá una línea en blanco en un argumento vacío, mientras que el de una línea ignorará una línea en blanco. En este caso, el comportamiento de una línea es lo que preferiría de todos modos, así que doble bonificación por ser compacto.
Lo usaría IFS=$'\n' cmd $(<file)
pero no funciona, porque $(<file)
se interpreta para formar la línea de comando antes de que IFS=$'\n'
surta efecto.
Aunque no funciona en mi caso, ahora he aprendido que muchas herramientas admiten líneas de terminación en null (\000)
lugar de newline (\n)
lo que facilita mucho esto al tratar, por ejemplo, los nombres de archivos, que son fuentes comunes de estas situaciones :
find / -name '*.config' -print0 | xargs -0 md5
alimenta una lista de nombres de archivos completamente calificados como argumentos para md5 sin ningún problema o interpolación o lo que sea. Eso lleva a la solución no incorporada
tr "\n" "\000" <file | xargs -0 cmd
aunque esto también ignora las líneas vacías, aunque captura líneas que solo tienen espacios en blanco.