Angesichts dieser Dateinamen:
$ ls -1
file
file name
otherfile
bash
selbst funktioniert perfekt mit eingebetteten Leerzeichen:
$ 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
#?
Manchmal möchte ich jedoch vielleicht nicht mit jeder Datei arbeiten oder sogar ausschließlich in $PWD
, wo find
ist kommt herein. Was nominell auch mit Leerzeichen umgeht:
$ find -type f -name file*
./file
./file name
./directory/file
./directory/file name
Ich versuche, eine whispace-sichere Version dieses Skriptlets zusammenzustellen, die die Ausgabe von find
übernimmt und präsentieren Sie es in select
:
$ select file in $(find -type f -name file); do echo $file; break; done
1) ./file
2) ./directory/file
Dies explodiert jedoch mit Leerzeichen in den Dateinamen:
$ 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
Normalerweise würde ich das umgehen, indem ich mit IFS
herumspielen würde . Allerdings:
$ 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'
Was ist die Lösung dafür?
Akzeptierte Antwort:
Wenn Sie nur Leerzeichen und Tabulatoren (keine eingebetteten Zeilenumbrüche) verarbeiten müssen, können Sie mapfile
verwenden (oder sein Synonym readarray
), um in ein Array zu lesen, z. gegeben
$ ls -1
file
other file
somefile
dann
$ 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
Wenn Sie tun Zeilenumbrüche verarbeiten müssen, und Ihre bash
Version stellt eine durch Null getrennte mapfile
bereit , dann können Sie das ändern in IFS= mapfile -t -d '' files < <(find . -type f -print0)
. Andernfalls stellen Sie ein äquivalentes Array aus dem durch Null getrennten find
zusammen Ausgabe mit read
Schleife:
$ 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
das -d
Option wurde zu mapfile
hinzugefügt in bash
Version 4.4 iirc