Chciałem wiedzieć, czy jest jakiś sposób odczytu z dwóch plików wejściowych w zagnieżdżonej pętli while po jednej linii na raz. Załóżmy na przykład, że mam dwa pliki FileA
i FileB
.
Plik a:
[jaypal:~/Temp] cat filea
this is File A line1
this is File A line2
this is File A line3
Plik B:
[jaypal:~/Temp] cat fileb
this is File B line1
this is File B line2
this is File B line3
Aktualny przykładowy skrypt:
[jaypal:~/Temp] cat read.sh
#!/bin/bash
while read lineA
do echo $lineA
while read lineB
do echo $lineB
done < fileb
done < filea
Wykonanie:
[jaypal:~/Temp] ./read.sh
this is File A line1
this is File B line1
this is File B line2
this is File B line3
this is File A line2
this is File B line1
this is File B line2
this is File B line3
this is File A line3
this is File B line1
this is File B line2
this is File B line3
Problem i pożądane wyjście:
Powoduje to całkowite zapętlenie pliku FileB dla każdej linii w FileA. Próbowałem użyć kontynuacji, przerwania, wyjścia, ale żaden z nich nie jest przeznaczony do uzyskania oczekiwanego rezultatu. Chciałbym, aby skrypt odczytał tylko jedną linię z pliku A, a następnie jedną linię z pliku B i opuścił pętlę i kontynuował z drugą linią pliku A i drugą linią pliku B. Coś podobnego do następującego skryptu -
[jaypal:~/Temp] cat read1.sh
#!/bin/bash
count=1
while read lineA
do echo $lineA
lineB=`sed -n "$count"p fileb`
echo $lineB
count=`expr $count + 1`
done < filea
[jaypal:~/Temp] ./read1.sh
this is File A line1
this is File B line1
this is File A line2
this is File B line2
this is File A line3
this is File B line3
Czy można to osiągnąć za pomocą pętli while?
bash
shell-script
io-redirection
jaypal singh
źródło
źródło
paste -d '\n' file1 file2
Odpowiedzi:
Jeśli wiesz na pewno, że jakiś znak nigdy nie pojawi się w pierwszym pliku, możesz użyć wklejania.
Przykład wklejania przy użyciu domyślnej karty ogranicznika:
Przykład wklejania przy użyciu
@
:Zauważ, że wystarczy, jeśli znak nie pojawi się w pierwszym pliku. Jest tak, ponieważ
read
zignorujeIFS
podczas wypełniania ostatniej zmiennej. Więc nawet jeśli@
występuje w drugim pliku, nie zostanie podzielony.Przykład wklejania przy użyciu niektórych funkcji bash dla prawdopodobnie czystszego kodu:
Zastosowane funkcje Bash: ansi c string (
$'\t'
) i proces substytucji (<(...)
), aby uniknąć pętli while w problemie podpowłoki .Jeśli nie możesz być pewien, że w obu plikach nigdy nie wystąpi żaden znak, możesz użyć deskryptorów plików .
Niewiele testowane. Może się zerwać na pustych liniach.
Deskryptory plików o numerach 0, 1 i 2 są już używane odpowiednio dla stdin, stdout i stderr. Deskryptory plików od 3 i więcej są (zwykle) darmowe. Podręcznik bash ostrzega przed użyciem deskryptorów plików większych niż 9, ponieważ są one „używane wewnętrznie”.
Zauważ, że otwarte deskryptory plików są dziedziczone po funkcjach powłoki i programach zewnętrznych. Funkcje i programy dziedziczące otwarty deskryptor pliku mogą odczytywać deskryptor pliku (i zapisywać do niego). Przed wywołaniem funkcji lub programu zewnętrznego należy zamknąć wszystkie deskryptory plików, które nie są wymagane.
Oto ten sam program jak powyżej z faktyczną pracą (druk) oddzieloną od meta-pracy (czytanie linii po linii z dwóch plików równolegle).
Teraz udajemy, że nie mamy kontroli nad kodem pracy i ten kod z jakiegokolwiek powodu próbuje odczytać z deskryptora pliku 3.
Oto przykładowy wynik. Zauważ, że druga linia z pierwszego pliku jest „skradziona” z pętli.
Oto, w jaki sposób należy zamknąć deskryptory plików przed wywołaniem zewnętrznego kodu (lub dowolnego innego kodu w tym zakresie).
źródło
Otwórz dwa pliki na różnych deskryptorach plików . Przekieruj wejście
read
wbudowanego do deskryptora, do którego podłączony jest żądany plik. W bash / ksh / zsh możesz pisaćread -u 3
zamiastread <&3
.Ten fragment kodu zatrzymuje się po przetworzeniu najkrótszego pliku. Zobacz Odczytywanie dwóch plików w pętli IFS while - Czy w takim przypadku można uzyskać wynik zerowej różnicy? jeśli chcesz kontynuować przetwarzanie do końca obu plików.
Zobacz także Kiedy użyjesz dodatkowego deskryptora pliku? w celu uzyskania dodatkowych informacji o deskryptorach plików i dlaczego tak często używa się opcji „while IFS = read” zamiast „IFS =; podczas czytania ... dla wyjaśnienia
IFS= read -r
.źródło
Wiem, że chcesz skrypt powłoki, ale możesz rzucić okiem na
paste
polecenie.źródło
paste
też jest fajny.Spróbuj wykonać poniższe polecenie:
źródło
Alternatywnie, przypuszczam, że możesz slurpować plik do zmiennej tablicowej, wiążąc każdą linię pliku w tablicę [indeks_pliku_indeksu] za pomocą polecenia mapfile basha. Nie jestem jednak pewien, czy dotyczy to tylko wersji Bash3 wyższej czy Bash4.
http://wiki.bash-hackers.org/commands/builtin/mapfile
źródło