Skrypt pobiera adres URL, analizuje go pod kątem wymaganych pól i przekierowuje dane wyjściowe do zapisania w pliku plik.txt . Dane wyjściowe są zapisywane w nowym wierszu za każdym razem, gdy zostanie znalezione pole.
plik.txt
A Cat
A Dog
A Mouse
etc...
Chcę wziąć file.txt
i utworzyć z niego tablicę w nowym skrypcie, w którym każda linia ma być własną zmienną łańcuchową w tablicy. Do tej pory próbowałem:
#!/bin/bash
filename=file.txt
declare -a myArray
myArray=(`cat "$filename"`)
for (( i = 0 ; i < 9 ; i++))
do
echo "Element [$i]: ${myArray[$i]}"
done
Kiedy uruchamiam ten skrypt, białe znaki powodują, że słowa są dzielone, a zamiast pobierać
Pożądane wyjście
Element [0]: A Cat
Element [1]: A Dog
etc...
W końcu otrzymuję to:
Rzeczywista wydajność
Element [0]: A
Element [1]: Cat
Element [2]: A
Element [3]: Dog
etc...
Jak mogę dostosować pętlę poniżej tak, aby cały ciąg w każdym wierszu odpowiadał jeden do jednego z każdą zmienną w tablicy?
Odpowiedzi:
Użyj
mapfile
polecenia:mapfile -t myArray < file.txt
Błąd polega na użyciu
for
- idiomatyczny sposób na pętlę po wierszach pliku to:while IFS= read -r line; do echo ">>$line<<"; done < file.txt
Więcej informacji można znaleźć w BashFAQ / 005 .
źródło
while IFS= read -r; do lines+=("$REPLY"); done <file
.mapfile
nie będzie działał zgodnie z oczekiwaniami na wielu komputerach bez dodatkowych kroków. @ericslaw macs będą nadal dostarczane z bash 3.2.57 w najbliższej przyszłości. Nowsze wersje używają licencji, która wymagałaby od Apple udostępniania lub zezwalania na rzeczy, których nie chcą udostępniać lub na które nie chcą.mapfile
ireadarray
(które są synonimami) są dostępne w wersji Bash 4 i nowszych. Jeśli masz starszą wersję Bash, możesz użyć pętli do wczytania pliku do tablicy:arr=() while IFS= read -r line; do arr+=("$line") done < file
W przypadku, gdy plik ma niekompletną (brakującą nową linię) ostatnią linię, możesz skorzystać z tej alternatywy:
arr=() while IFS= read -r line || [[ "$line" ]]; do arr+=("$line") done < file
Związane z:
źródło
IFS= read -r line || [[ "$line" ]]
, aby zadziałało. W przeciwnym razie działa świetnie!do
?Ty też możesz to zrobić:
oldIFS="$IFS" IFS=$'\n' arr=($(<file)) IFS="$oldIFS" echo "${arr[1]}" # It will print `A Dog`.
Uwaga:
Nadal występuje rozszerzenie nazwy pliku. Na przykład, jeśli istnieje wiersz z literałem
*
, zostanie on rozszerzony na wszystkie pliki w bieżącym folderze. Więc używaj go tylko wtedy, gdy twój plik jest wolny od tego rodzaju scenariuszy.źródło
IFS
tylko tymczasowo (aby odzyskał swoją pierwotną wartość po tym poleceniu), jednocześnie utrzymując przypisanie doarr
?IFS=$'\n' arr=($(echo 'a 1'; echo '*'; echo 'b 2')); printf "%s\n" "${arr[@]}"
IFS=... command
nie zmienia sięIFS
w bieżącej powłoce. JednakIFS=... other_variable=...
(bez żadnego polecenia) zmienia zarównoIFS
iwother_variable
bieżącej powłoce.arr=
notacja (w porównaniu domapfile
/readarray
).Możesz po prostu odczytać każdy wiersz z pliku i przypisać go do tablicy.
#!/bin/bash i=0 while read line do arr[$i]="$line" i=$((i+1)) done < file.txt
źródło
Użyj pliku mapy lub przeczytaj -a
Zawsze sprawdzaj swój kod za pomocą shellcheck . Często daje prawidłową odpowiedź. W tym przypadku SC2207 obejmuje wczytywanie do tablicy pliku, który zawiera wartości oddzielone spacjami lub nowej linii.
Nie rób tego
Pliki z wartościami oddzielonymi znakami nowej linii
mapfile -t array < <(mycommand)
Pliki z wartościami oddzielonymi spacjami
IFS=" " read -r -a array <<< "$(mycommand)"
Na stronie sprawdzania powłoki znajdziesz uzasadnienie, dlaczego jest to uważane za najlepszą praktykę.
źródło
Ta odpowiedź mówi, aby użyć
mapfile -t myArray < file.txt
Zrobiłem podkładkę dla
mapfile
jeśli chcesz używaćmapfile
na bash <4.x z jakiegokolwiek powodu. Używa istniejącegomapfile
polecenia, jeśli używasz bash> = 4.xObecnie tylko opcje
-d
i-t
działają. Ale to powinno wystarczyć dla powyższego polecenia. Testowałem tylko na macOS. W systemie macOS Sierra 10.12.6 bash systemowy to3.2.57(1)-release
. Więc podkładka może się przydać. Możesz także zaktualizować bash za pomocą homebrew, samodzielnie zbudować bash itp.Używa tej techniki do ustawiania zmiennych na jednym stosie wywołań.
źródło