Étant donné ces noms de fichiers :
$ ls -1
file
file name
otherfile
bash
lui-même fonctionne parfaitement avec les espaces blancs intégrés :
$ 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
#?
Cependant, parfois je ne veux pas travailler avec tous les fichiers, ou même strictement dans $PWD
, où find
entre. Qui gère également les espaces blancs :
$ find -type f -name file*
./file
./file name
./directory/file
./directory/file name
J'essaie de concocter une version whispace-safe de ce scriptlet qui prendra la sortie de find
et présentez-le dans select
:
$ select file in $(find -type f -name file); do echo $file; break; done
1) ./file
2) ./directory/file
Cependant, cela explose avec des espaces dans les noms de fichiers :
$ 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
Normalement, je contournerais ce problème en jouant avec IFS
. Cependant :
$ 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'
Quelle est la solution à cela ?
Réponse acceptée :
Si vous n'avez besoin que de gérer les espaces et les tabulations (et non les sauts de ligne intégrés), vous pouvez utiliser mapfile
(ou son synonyme, readarray
) pour lire dans un tableau, par ex. donné
$ ls -1
file
other file
somefile
alors
$ 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 vous faites besoin de gérer les nouvelles lignes et votre bash
version fournit un mapfile
délimité par des valeurs nulles , vous pouvez alors le modifier en IFS= mapfile -t -d '' files < <(find . -type f -print0)
. Sinon, assemblez un tableau équivalent à partir de find
délimité par null sortie à l'aide d'un read
boucle :
$ 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
le -d
l'option a été ajoutée au mapfile
dans bash
version 4.4 irc