it-swarm.com.de

Erstellen eines Arrays aus einer Textdatei in Bash

Ein Skript verwendet eine URL, analysiert sie nach den erforderlichen Feldern und leitet die Ausgabe in eine Datei um, file.txt. 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 es gerne nehmen file.txt und erstellen daraus ein Array in einem neuen Skript, in dem jede Zeile eine eigene Zeichenfolgenvariable im Array ist. 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, werden Wörter durch Leerzeichen getrennt und nicht durch Leerzeichen ersetzt

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 darunter so einstellen, dass die gesamte Zeichenfolge in jeder Zeile mit jeder Variablen im Array eins zu eins übereinstimmt?

67
user2856414

Verwenden Sie den Befehl mapfile :

mapfile -t myArray < file.txt

Der Fehler besteht in der Verwendung von for - die idiomatische Methode zum Durchlaufen der Zeilen einer Datei lautet:

while IFS= read -r line; do echo ">>$line<<"; done < file.txt

Siehe BashFAQ/005 für weitere Details.

79
glenn jackman

mapfile und readarray (synonym) sind in Bash Version 4 und höher verfügbar. Wenn Sie eine ältere Version von Bash haben, können Sie die Datei mit einer Schleife in ein Array einlesen:

arr=()
while IFS= read -r line; do
  arr+=("$line")
done < file

Falls die Datei eine unvollständige (fehlende) letzte Zeile enthält, können Sie diese Alternative verwenden:

arr=()
while IFS= read -r line || [[ "$line" ]]  do
  arr+=("$line")
done < file

Verbunden:

13
codeforester

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 zum Beispiel eine Zeile mit einem wörtlichen * wird auf alle Dateien im aktuellen Ordner erweitert. Verwenden Sie es also nur, wenn Ihre Datei frei von solchen Szenarien ist.

7
Jahid

Sie können einfach jede Zeile aus der Datei lesen und sie einem Array zuweisen.

#!/bin/bash
i=0
while read line 
do
        arr[$i]="$line"
        i=$((i+1))
done < file.txt
4
Prateek Joshi

Verwenden Sie mapfile oder read -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, die entweder durch Leerzeichen oder durch Zeilenumbrüche getrennte Werte enthält, in einem Array.

Mach das nicht

array=( $(mycommand) )

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 Best Practice gilt.

Diese Antwort sagt zu verwenden

mapfile -t myArray < file.txt

Ich habe ein shim für mapfile erstellt, wenn Sie mapfile für bash <4.x verwenden möchten, aus welchem ​​Grund auch immer. Es verwendet den vorhandenen Befehl mapfile, wenn Sie bash> = 4.x ausführen

Derzeit funktionieren nur die Optionen -d Und -t. Aber das sollte für den obigen Befehl ausreichen. Ich habe nur auf macOS getestet. Unter macOS Sierra 10.12.6 lautet die Systembash 3.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.

Es verwendet diese Technik , um Variablen für einen Aufrufstapel einzurichten.

1
dosentmatter