Ich versuche, das Ergebnis als Arrays zu speichern ... Hier ist mein Code:
#!/bin/bash
echo "input : "
read input
echo "searching file with this pattern '${input}' under present directory"
array=`find . -name ${input}`
len=${#array[*]}
echo "found : ${len}"
i=0
while [ $i -lt $len ]
do
echo ${array[$i]}
let i++
done
Ich bekomme 2 .txt-Dateien unter dem aktuellen Verzeichnis . Daher erwarte ich '2' als Ergebnis von ${len}
. Es wird jedoch 1 ..__ ausgegeben. Der Grund dafür ist, dass alle Ergebnisse von find als ein Element verwendet werden . Wie kann ich das beheben? Vielen Dank.
P.S Ich habe in Stack OverFlow mehrere Lösungen zu einem ähnlichen Problem gefunden. Es ist jedoch etwas anders, so dass ich mich bei mir bewerben kann. Ich muss das Ergebnis vor der Schleife in einer Variablen speichern. Danke noch einmal.
Hier ist eine Lösung, um die Ausgabe von find
in ein bash
-Array zu bekommen:
array=()
while IFS= read -r -d $'\0'; do
array+=("$REPLY")
done < <(find . -name "${input}" -print0)
Dies ist schwierig, da Dateinamen im Allgemeinen Leerzeichen, neue Zeilen und andere Skript-feindliche Zeichen enthalten können. Die einzige Möglichkeit, find
zu verwenden und die Dateinamen sicher voneinander zu trennen, besteht in der Verwendung von -print0
, bei dem die Dateinamen mit einem Nullzeichen getrennt werden. Dies wäre nicht unbequem, wenn die readarray
/mapfile
-Funktionen von bash nullgetrennte Zeichenketten unterstützen, dies aber nicht. Bashs read
tut und das führt uns zu der Schleife darüber.
Die erste Zeile erstellt ein leeres Array: array=()
Bei jeder Ausführung der Anweisung read
wird ein durch Null getrennter Dateiname aus der Standardeingabe gelesen. Die -r
-Option weist read
an, Backslash-Zeichen in Ruhe zu lassen. Der -d $'\0'
teilt der read
mit, dass die Eingabe nullgetrennt sein wird. Da wir den Namen auf read
auslassen, setzt die Shell die Eingabe in den Standardnamen: REPLY
.
Die array+=("$REPLY")
-Anweisung fügt den neuen Dateinamen an das Array array
an.
Die letzte Zeile kombiniert Umleitung und Befehlssubstitution, um die Ausgabe von find
an die Standardeingabe der while
-Schleife zu übergeben.
Wenn wir keine Prozessersetzung verwendeten, könnte die Schleife folgendermaßen geschrieben werden:
array=()
find . -name "${input}" -print0 >tmpfile
while IFS= read -r -d $'\0'; do
array+=("$REPLY")
done <tmpfile
rm -f tmpfile
Im obigen Abschnitt wird die Ausgabe von find
in einer temporären Datei gespeichert und diese Datei wird als Standardeingabe für die while-Schleife verwendet. Die Idee der Prozessersetzung besteht darin, solche temporären Dateien unnötig zu machen. Anstatt die while
-Schleife von stdin von tmpfile
abrufen zu lassen, können wir ihre stdin von <(find . -name ${input} -print0)
bekommen.
Prozessersetzung ist weithin nützlich. An vielen Stellen, an denen ein Befehl read aus einer Datei verwenden möchte, können Sie anstelle des Dateinamens die Prozessersetzung <(...)
angeben. Es gibt ein analoges Formular, >(...)
, das anstelle eines Dateinamens verwendet werden kann, bei dem der Befehl write in die Datei schreiben möchte.
Wie Arrays ist die Prozessersetzung ein Merkmal von bash und anderen erweiterten Shells. Es gehört nicht zum POSIX-Standard.
Der folgende Befehl erstellt eine Shell-Variable, kein Shell-Array:
array=`find . -name "${input}"`
Wenn Sie ein Array erstellen möchten, müssen Sie die Ausgabe von find mit Parens versehen. Naiv könnte man:
array=(`find . -name "${input}"`) # don't do this
Das Problem ist, dass die Shell eine Word-Aufteilung für die Ergebnisse von find
durchführt, so dass die Elemente des Arrays nicht garantiert Ihren Vorstellungen entsprechen.
Wenn Sie bash
4 oder höher verwenden, können Sie Ihre Verwendung von find
durch ersetzen
shopt -s globstar nullglob
array=( **/*"$input"* )
Das **
-Muster, das von globstar
aktiviert wird, stimmt mit 0 oder mehr Verzeichnissen überein, sodass das Muster mit einer beliebigen Tiefe im aktuellen Verzeichnis übereinstimmen kann. Ohne die Option nullglob
wird das Muster (nach der Parametererweiterung) buchstäblich behandelt. Ohne Übereinstimmungen haben Sie ein Array mit einer einzelnen Zeichenfolge anstelle eines leeren Arrays.
Fügen Sie die Option dotglob
auch in der ersten Zeile hinzu, wenn Sie versteckte Verzeichnisse (wie .ssh
) durchsuchen und ausgeblendete Dateien (wie .bashrc
) abgleichen möchten.
sie können etwas wie .__ versuchen.
array=(`find . -type f | sort -r | head -2`)
, und um die Array-Werte zu drucken, können Sie etwas wie echo "${array[*]}"
versuchenBash 4.4 hat eine -d
-Option für readarray
mapfile
EINGEF&UUML;HRT, SO DASS DIES NUN MIT GEL&OUML;ST WERDEN KANN
readarray -d '' array < <(find . -name "$input" -print0)
F&UUML;R EINE METHODE, DIE MIT BELIEBIGEN DATEINAMEN ARBEITET, EINSCHLIE&SZLIG;LICH LEERZEICHEN, ZEILENUMBR&UUML;CHEN UND GLOBBING-ZEICHEN.
AUS DEM MANUAL (UNTER AUSLASSUNG ANDERER OPTIONEN):
mapfile [-d delim] [array]
-d
DAS ERSTE ZEICHEN VON _/delim
wird verwendet, um jede Eingabezeile zu beenden, anstatt eine Zeilenschaltung. Wenndelim
die leere Zeichenfolge ist, beendetmapfile
eine Zeile, wenn sie ein NUL-Zeichen liest.
Und readarray
ist nur ein Synonym für mapfile
.
In Bash hilft $(<any_Shell_cmd>)
, einen Befehl auszuführen und die Ausgabe zu erfassen. Die Übergabe an IFS
mit \n
als Trennzeichen hilft beim Konvertieren in ein Array.
IFS='\n' read -r -a txt_files <<< $(find /path/to/dir -name "*.txt")