Dados estos nombres de archivo:
$ ls -1
file
file name
otherfile
bash
funciona perfectamente bien con espacios en blanco incrustados:
$ for file in *; do echo "$file"; done
file
file name
otherfile
$ select file in *; do echo "$file"; done
1) file
2) file name
3) otherfile
#?
Sin embargo, a veces es posible que no quiera trabajar con todos los archivos, o incluso estrictamente en $PWD
, que es donde find
entra. Que también maneja los espacios en blanco nominalmente:
$ find -type f -name file*
./file
./file name
./directory/file
./directory/file name
Estoy tratando de inventar una versión segura de whispace de este scriptlet que tomará la salida de find
y presentarlo en select
:
$ select file in $(find -type f -name file); do echo $file; break; done
1) ./file
2) ./directory/file
Sin embargo, esto explota con espacios en blanco en los nombres de archivo:
$ select file in $(find -type f -name file*); do echo $file; break; done
1) ./file 3) name 5) ./directory/file
2) ./file 4) ./directory/file 6) name
Normalmente, solucionaría esto jugando con IFS
. Sin embargo:
$ IFS=$'n' select file in $(find -type f -name file*); do echo $file; break; done
-bash: syntax error near unexpected token `do'
$ IFS='n' select file in $(find -type f -name file*); do echo $file; break; done
-bash: syntax error near unexpected token `do'
¿Cuál es la solución a esto?
Respuesta aceptada:
Si solo necesita manejar espacios y tabulaciones (no líneas nuevas incrustadas), puede usar mapfile
(o su sinónimo, readarray
) para leer en una matriz, p. dado
$ ls -1
file
other file
somefile
entonces
$ IFS= mapfile -t files < <(find . -type f)
$ select f in "${files[@]}"; do ls "$f"; break; done
1) ./file
2) ./somefile
3) ./other file
#? 3
./other file
Si haces necesita manejar saltos de línea, y su bash
versión proporciona un mapfile
delimitado por nulos , luego puede modificar eso a IFS= mapfile -t -d '' files < <(find . -type f -print0)
. De lo contrario, ensamble una matriz equivalente a partir de find
delimitado por nulos salida usando un read
bucle:
$ touch $'filenamenwithnnewlines'
$
$ files=()
$ while IFS= read -r -d '' f; do files+=("$f"); done < <(find . -type f -print0)
$
$ select f in "${files[@]}"; do ls "$f"; break; done
1) ./file
2) ./somefile
3) ./other file
4) ./filename
with
newlines
#? 4
./filename?with?newlines
el -d
se agregó la opción a mapfile
en bash
versión 4.4 iirc