Mam następujący plik .txt:
Marco
Paolo
Antonio
Chcę go czytać wiersz po wierszu i dla każdej linii chcę przypisać wartość zmiennej .txt do zmiennej. Zakładając, że moja zmienna jest $name
taka, przepływ jest następujący:
- Przeczytaj pierwszy wiersz z pliku
- Przypisz
$name
= „Marco” - Wykonuj niektóre zadania za pomocą
$name
- Czytaj drugi wiersz z pliku
- Przypisz
$name
= „Paolo”
Odpowiedzi:
Poniżej czytany jest plik przekazywany jako argument linia po linii:
Jest to standardowa forma odczytu linii z pliku w pętli. Wyjaśnienie:
IFS=
(lubIFS=''
) zapobiega przycinaniu wiodących / końcowych białych znaków.-r
zapobiega interpretacji ucieczek odwrotnego ukośnika.Lub możesz umieścić go w skrypcie pomocniczym pliku bash, przykładowa zawartość:
Jeśli powyższe zapisano w skrypcie z nazwą pliku
readfile
, można go uruchomić w następujący sposób:Jeśli plik nie jest standardowym plikiem tekstowym POSIX (= nie zakończony znakiem nowej linii), można zmodyfikować pętlę, aby obsługiwała końcowe wiersze częściowe:
Tutaj
|| [[ -n $line ]]
zapobiega ignorowaniu ostatniego wiersza, jeśli nie kończy się on na\n
(ponieważread
zwraca niezerowy kod wyjścia, gdy napotka EOF).Jeśli polecenia wewnątrz pętli również odczytują ze standardowego wejścia,
read
można użyć innego deskryptora pliku do czegoś innego (unikaj standardowych deskryptorów plików ), np .:(Powłoki inne niż Bash mogą nie wiedzieć
read -u3
; użyjread <&3
zamiast tego.)źródło
ssh
bez-n
flagi skutecznie spowoduje ucieczkę z pętli. Prawdopodobnie jest to dobry powód, ale zajęło mi trochę czasu, aby ustalić, co spowodowało awarię mojego kodu, zanim to odkryłem.ffmpeg
spożywaniem standardowego wejścia. Dodaj</dev/null
doffmpeg
linii i nie będzie w stanie, ani użyć alternatywnego FD dla pętli. To podejście „alternatywnego FD” wyglądawhile IFS='' read -r line <&3 || [[ -n "$line" ]]; do ...; done 3<"$1"
..sh
rozszerzenia. Pliki wykonywalne w systemie UNIX zazwyczaj nie mają żadnych rozszerzeń (nie uruchamiaszls.elf
), a szesnastkowy bash (i tylko narzędzia bash, takie jak[[ ]]
) oraz rozszerzenie sugerujące kompatybilność sh POSIX są wewnętrznie wewnętrznie sprzeczne.Zachęcam do korzystania z
-r
flagi,read
której skrót oznacza:Cytuję od
man 1 read
.Inną rzeczą jest przyjęcie nazwy pliku jako argumentu.
Oto zaktualizowany kod:
źródło
sh
, niebash
; rozszerzone polecenie testowe użyte w|| [[ -n "$line" ]]
składni w zaakceptowanej odpowiedzi to bzdura. To powiedziawszy, ta składnia faktycznie ma istotne znaczenie: powoduje, że pętla kontynuuje ostatnią linię w pliku wejściowym, nawet jeśli nie ma nowej linii. Jeśli chcesz to zrobić w sposób zgodny z POSIX, powinieneś raczej|| [ -n "$line" ]
użyć[
zamiast[[
.IFS=
dlaread
zapobiegać przycinanie spacje.Korzystanie z następującego szablonu Bash powinno umożliwiać odczytanie jednej wartości na raz z pliku i przetworzenie jej.
źródło
*
.źródło
Enter
po ostatniej linii), w przeciwnym razie ostatnia linia zostanie zignorowana. Przynajmniej tak się stało.Wiele osób opublikowało nadmiernie zoptymalizowane rozwiązanie. Nie sądzę, aby było to nieprawidłowe, ale pokornie uważam, że pożądane będzie mniej zoptymalizowane rozwiązanie, aby każdy mógł łatwo zrozumieć, jak to działa. Oto moja propozycja:
źródło
Posługiwać się:
Jeśli ustawiłeś
IFS
inaczej, otrzymasz dziwne wyniki.źródło
*
w wierszu? W każdym razie jest to antypattern . Nie czytaj wierszy za .read
podejście to podejście oparte na najlepszych praktykach w drodze konsensusu społeczności . Zastrzeżenie, o którym wspominasz w komentarzu, ma zastosowanie, gdy twoja pętla uruchamia polecenia (takie jakffmpeg
), które odczytują ze standardowego wejścia, rozwiązane w trywialny sposób za pomocą niedyskryminacyjnego FD dla pętli lub przekierowującego wejście takich poleceń. Natomiast obejście błędu globbing wfor
podejściu pętli oznacza wprowadzenie (a następnie konieczność cofnięcia) zmian ustawień globalnej powłoki.for
podejście pętli użyć tutaj oznacza, że cała zawartość musi być odczytywane przed pętla może zacząć realizować w ogóle, co czyni go całkowicie bezużyteczne, jeśli jesteś zapętlenie nad gigabajtów danych, nawet jeśli mają wyłączone globbing;while read
pętla potrzebuje nie więcej niż jednej linii danych za przechowywanie w czasie, dzięki czemu można ją zacząć realizować podczas gdy zawartość generujący podproces nadal działa (a więc jest użyteczny dla celów transmisji strumieniowej), a także ma ograniczone zużycie pamięci.while
oparte na podejściu wydaje się mieć * charakterystyczne problemy. Zobacz komentarze do zaakceptowanej odpowiedzi powyżej. Jednak nie kłóci się o to, że pliki są antypatternem.Jeśli potrzebujesz przetworzyć zarówno plik wejściowy, jak i dane wejściowe użytkownika (lub cokolwiek innego ze standardowego wejścia), skorzystaj z następującego rozwiązania:
Na podstawie zaakceptowanej odpowiedzi i samouczka przekierowania bash-hakerów .
Tutaj otwieramy deskryptor pliku 3 dla pliku przekazanego jako argument skryptu i informujemy
read
aby użyć tego deskryptora jako input (-u 3
). Dlatego pozostawiamy domyślny deskryptor wejściowy (0) podłączony do terminala lub innego źródła wejściowego, zdolnego do odczytu danych wejściowych użytkownika.źródło
Do prawidłowej obsługi błędów:
źródło
Po prostu wydrukuje zawartość pliku:
źródło
Użyj narzędzia IFS (wewnętrzny separator pól) w bash, definiuje znak za pomocą, aby podzielić linie na tokeny, domyślnie zawiera < tab > / < space > / < newLine >
krok 1 : Załaduj dane pliku i wstaw do listy:
krok 2 : teraz iteruj i wydrukuj wynik:
indeks specyficzny dla echa w tablicy : Dostęp do zmiennej w tablicy:
źródło