GNU/Linux >> Tutoriales Linux >  >> Linux

Bash:¿Uso de procedimiento seguro para espacios en blanco de Find Into Select?

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

Relacionado:acing -Encontrar significado- ¡Búsqueda en el diccionario!
Linux
  1. Cómo usar los comandos del historial de Bash

  2. ¿Cómo registrar cada comando escrito en Bash y cada operación de archivo?

  3. ¿Buscar el archivo de registro de Firefox?

  4. ¿Qué método utiliza Descomprimir para encontrar un solo archivo en un archivo?

  5. buscar y copiar archivos usando Bash

Bash:Agregar al archivo

Cómo usar operadores de prueba de archivos Bash en Linux

35 ejemplos de secuencias de comandos Bash

Cómo encontrar archivos con docenas de criterios con el comando Bash Find

Cómo hacer eco en un archivo

Cómo usar Sed para buscar y reemplazar una cadena en un archivo