GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Bash:Whitespace-sichere prozedurale Verwendung von Find Into Select?

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

Verwandte:acing -Bedeutung finden- Dictionary Lookup!
Linux
  1. So verwenden Sie Bash-Verlaufsbefehle

  2. Wie protokolliere ich jeden in Bash eingegebenen Befehl und jede Dateioperation?

  3. Suchen und kopieren Sie die Datei mit Bash

  4. Bash-Funktion, um das neueste Dateiübereinstimmungsmuster zu finden

  5. Dateierweiterungen in Bash rekursiv ändern

Bash:An Datei anhängen

So verwenden Sie Bash-Dateitestoperatoren in Linux

35 Bash-Skriptbeispiele

So finden Sie Dateien mit Dutzenden von Kriterien mit dem Bash-Suchbefehl

Wie Echo in Datei

So verwenden Sie Sed zum Suchen und Ersetzen einer Zeichenfolge in einer Datei