Ein Skript nimmt eine URL, analysiert sie nach den erforderlichen Feldern und leitet ihre Ausgabe zum Speichern in die Datei file.txt um . Die Ausgabe wird jedes Mal in einer neuen Zeile gespeichert, wenn ein Feld gefunden wurde.
file.txt
A Cat
A Dog
A Mouse
etc...
Ich möchte file.txt
ein Array daraus in einem neuen Skript erstellen, wobei jede Zeile eine eigene Zeichenfolgenvariable im Array sein soll. Bisher habe ich versucht:
#!/bin/bash
filename=file.txt
declare -a myArray
myArray=(`cat "$filename"`)
for (( i = 0 ; i < 9 ; i++))
do
echo "Element [$i]: ${myArray[$i]}"
done
Wenn ich dieses Skript ausführe, führt ein Leerzeichen dazu, dass Wörter geteilt werden und nicht
Gewünschte Ausgabe
Element [0]: A Cat
Element [1]: A Dog
etc...
Am Ende bekomme ich Folgendes:
Tatsächliche Ausgabe
Element [0]: A
Element [1]: Cat
Element [2]: A
Element [3]: Dog
etc...
Wie kann ich die Schleife unten so einstellen, dass die gesamte Zeichenfolge in jeder Zeile mit jeder Variablen im Array eins zu eins übereinstimmt?
Antworten:
Verwenden Sie den
mapfile
Befehl:mapfile -t myArray < file.txt
Der Fehler wird verwendet
for
- die idiomatische Methode zum Überlaufen von Zeilen einer Datei ist:while IFS= read -r line; do echo ">>$line<<"; done < file.txt
Weitere Informationen finden Sie unter BashFAQ / 005 .
quelle
while IFS= read -r; do lines+=("$REPLY"); done <file
.mapfile
wird, auf vielen Computern ohne zusätzliche Schritte nicht wie erwartet ausgeführt wird. @ericslaw Macs werden auf absehbare Zeit weiterhin mit Bash 3.2.57 ausgeliefert. Neuere Versionen verwenden eine Lizenz, für die Apple Dinge freigeben oder zulassen muss, die sie nicht freigeben oder zulassen möchten.mapfile
undreadarray
(die synonym sind) sind in Bash Version 4 und höher verfügbar. Wenn Sie eine ältere Version von Bash haben, können Sie die Datei mithilfe einer Schleife in ein Array einlesen:arr=() while IFS= read -r line; do arr+=("$line") done < file
Falls die Datei eine unvollständige (fehlende neue Zeile) letzte Zeile enthält, können Sie diese Alternative verwenden:
arr=() while IFS= read -r line || [[ "$line" ]]; do arr+=("$line") done < file
Verbunden:
quelle
IFS= read -r line || [[ "$line" ]]
damit es funktioniert. Ansonsten funktioniert es super!do
?Sie können dies auch tun:
oldIFS="$IFS" IFS=$'\n' arr=($(<file)) IFS="$oldIFS" echo "${arr[1]}" # It will print `A Dog`.
Hinweis:
Die Dateinamenerweiterung erfolgt weiterhin. Wenn beispielsweise eine Zeile mit einem Literal vorhanden ist
*
, wird diese auf alle Dateien im aktuellen Ordner erweitert. Verwenden Sie es also nur, wenn Ihre Datei frei von solchen Szenarien ist.quelle
IFS
nur vorübergehend festzulegen (damit der ursprüngliche Wert nach diesem Befehl wiederhergestellt wird), während die Zuweisung an beibehalten wirdarr
?IFS=$'\n' arr=($(echo 'a 1'; echo '*'; echo 'b 2')); printf "%s\n" "${arr[@]}"
IFS=... command
ändert sich nichtIFS
in der aktuellen Shell. JedochIFS=... other_variable=...
(ohne Befehl) nicht beide ändernIFS
undother_variable
in dem aktuell Shell.arr=
Notation gefällt (im Vergleich zumapfile
/readarray
).Sie können einfach jede Zeile aus der Datei lesen und einem Array zuweisen.
#!/bin/bash i=0 while read line do arr[$i]="$line" i=$((i+1)) done < file.txt
quelle
Verwenden Sie Mapfile oder lesen Sie -a
Überprüfen Sie Ihren Code immer mit Shellcheck . Es wird Ihnen oft die richtige Antwort geben. In diesem Fall behandelt SC2207 das Lesen einer Datei, deren Werte entweder durch Leerzeichen oder durch Zeilenumbrüche getrennt sind, in ein Array.
Tu das nicht
Dateien mit durch Zeilenumbrüche getrennten Werten
mapfile -t array < <(mycommand)
Dateien mit durch Leerzeichen getrennten Werten
IFS=" " read -r -a array <<< "$(mycommand)"
Auf der Shellcheck-Seite erfahren Sie, warum dies als bewährte Methode angesehen wird.
quelle
Diese Antwort sagt zu verwenden
mapfile -t myArray < file.txt
Ich habe eine Unterlegscheibe gemacht,
mapfile
wenn Siemapfile
Bash <4.x aus irgendeinem Grund verwenden möchten . Es verwendet den vorhandenenmapfile
Befehl, wenn Sie sich auf bash> = 4.x befindenDerzeit nur Optionen
-d
und-t
Arbeit. Aber das sollte für diesen Befehl oben ausreichen. Ich habe nur unter macOS getestet. Unter macOS Sierra 10.12.6 ist die System-Bash3.2.57(1)-release
. So kann die Unterlegscheibe nützlich sein. Sie können Ihre Bash auch einfach mit Homebrew aktualisieren, Bash selbst erstellen usw.Mit dieser Technik werden Variablen für einen Aufrufstapel eingerichtet.
quelle