Czy istnieje sposób na określenie wielu zmiennych (nie tylko liczb całkowitych) w forpętlach w bash? Mogę mieć 2 pliki zawierające dowolny tekst, z którym musiałbym pracować.
Potrzebuję funkcjonalnie czegoś takiego:
for i in $(cat file1) and j in $(cat file2);do command $i $j;done
Po pierwsze, nie czytaj wierszy za pomocą , ponieważ istnieje kilka nieuniknionych problemów z czytaniem wierszy za pomocą podziału słów.
Zakładając pliki o równej długości lub jeśli chcesz zapętlać tylko do momentu odczytania krótszych dwóch plików, możliwe jest proste rozwiązanie.
while read -r x && read -r y <&3;do...done<file1 3<file2
Złożenie bardziej ogólnego rozwiązania jest trudne, ponieważ readzwraca false i kilka innych powodów. W tym przykładzie można odczytać dowolną liczbę strumieni i powrócić po najkrótszym lub najdłuższym wejściu.
#!/usr/bin/env bash# Open the given files and assign the resulting FDs to arrName.# openFDs arrname file1 [file2 ...]
openFDs(){local x y i arr=$1
[[-v $arr ]]||return1
shift
for x;do{ exec {y}<"$x";}2>/dev/null ||return1
printf -v "${arr}[i++]"%d "$y"done}# closeFDs FD1 [FD2 ...]
closeFDs(){local x
for x;do
exec {x}<&-done}# Read one line from each of the given FDs and assign the output to arrName.# If the first argument is -l, returns false only when all FDs reach EOF.# readN [ -l ] arrName FD1 [FD2 ...]
readN(){if[[ $1 ==-l ]];thenlocal longest
shift
elselocal longest=filocal i x y status arr=$1
[[-v $arr ]]||return1
shift
for x;doif IFS= read -ru "$x""${arr}[i]"||{ unset -v "${arr}[i]";[[ ${longest+_}]]&&return1;};then
status=0fi((i++))donereturn ${status:-1}}# readLines file1 [file2 ...]
readLines(){local-a fds lines
trap 'closeFDs "${fds[@]}"' RETURN
openFDs fds "$@"||return1while readN -l lines "${fds[@]}";do
printf '%-1s '"${lines[@]}"
echo
done}{
readLines /dev/fd/{3..6}||{ echo 'error occured'>&2; exit 1;}}<<<$'a\nb\nc\nd'3<&0<<<$'1\n2\n3\n4\n5'4<&0<<<$'x\ny\nz'5<&0<<<$'7\n8\n9\n10\n11\n12'6<&0# vim: set fenc=utf-8 ff=unix ts=4 sts=4 sw=4 ft=sh nowrap et:
Zatem w zależności od tego , czy readNpobiera -l, wynik jest albo
a 1 x 7
b 2 y 8
c 3 z 9
d 41051112
lub
a 1 x 7
b 2 y 8
c 3 z 9
Konieczność odczytu wielu strumieni w pętli bez zapisywania wszystkiego w wielu tablicach nie jest tak powszechna. Jeśli chcesz tylko czytać tablice, powinieneś rzucić okiem mapfile.
||nie działa dla mnie Jest w stanie przetworzyć plik1 następnie file2 , ale robi zachować pliki zsynchronizowane z &&, co wychodzi z while pętli podczas pierwszego EOF . - GNU bash 4.1.5
Peter.O
Nie miałem wolnego czasu na przetestowanie - tak, prawdopodobnie chciałbyś mieć oba elementy na iterację. Operator ||„listy” zwiera jak w większości języków. Na pewno odpowiedziano na to tysiąc razy przed ...
ormaaj
Nie chodzi o to, jak często coś wcześniej wspomniano. Przeciwnie, kod, który obecnie wyświetlasz w odpowiedzi , nie działa . Na podstawie twojego „ prawdopodobnie chcesz obu elementów ...”, brzmi to tak, jakbyś go jeszcze nie testował.
Peter.O
@ Peter.O Jestem świadomy. Zostało to naprawione.
ormaaj
2
Gotowe; gotowe - potrzebujesz dwóch forów i dwóch dones:
for i in $(< file1);dofor j in $(< file2);do echo $i $j;done;done
Plik 2 jest oczywiście przetwarzany raz dla każdego słowa w pliku 1.
Użycie <zamiast kota powinno w większości przypadków być niezwykłym przyrostem wydajności. Bez udziału podprocesu. (Niepewny co do ostatniego zdania).
Nieskompresowane:
for i in $(< file1)dofor j in $(< file2)do
echo $i $j
donedone
Jeśli nie lubisz czytać słów, ale wierszy i zachować białe znaki, użyj while i czytaj:
while read line;dowhile read second;do echo "${line}${second}";done<file2 ;done<file1
Jeśli chcesz dołączyć 2 pliki, a nie zagnieżdżać je:
Mówisz, że nie jest zaangażowany żaden podproces. Czy () nie jest podpowłoką? Nie chcę być zawieszona, ale nie jestem pewna, co się teraz dzieje. Na przykład wiem, że kiedy mam skrypt i nie chcę, aby na przykład polutował bieżącą powłokę za pomocą płyt CD, robię to wewnątrz (). Również uruchomienie (sleep 4) i na przykład po ps pokazuje, że proces jest nadal uruchomiony. Czy możesz proszę opracować.
Silverrocker
Cóż - przepraszam, bardzo działam tutaj bez fundamentu. Myślałem, że tak słyszę, ale może to tylko <porównanie cat. Nie jestem pewien, jak go przetestować i kiedy stanie się on semantycznie ważny. Jeśli wywoływane są potoki, zmienne w podprocesach nie pojawiają się w głównym procesie, ale nie mamy tutaj zmiennych. Przekreślam zdanie krytyczne, dopóki ktoś nie może go wyjaśnić.
użytkownik nieznany
0
whilema interesującą składnię. Możesz umieścić wiele poleceń przed do ... whilepętlą, a sprawa może wymagać żonglowania tą funkcją, w zależności od twoich szczególnych wymagań: czytasz do końca najdłuższego pliku, czy tylko do końca najkrótszego.
Na przykład read || readpo prostu nie działa (zgodnie z wymaganiami pytania), ponieważ gdy czytany jest pierwszy plik true, odczyt drugiego pliku jest pomijany, dopóki pierwszy plik nie zostanie odczytany od początku do końca ... Wtedy, ponieważ status jest nadal true, pętla while trwa i odczytuje drugi plik od początku do końca.
read && readodczyta pliki jednocześnie (synchronicznie), jeśli chcesz tylko czytać do najkrótszego pliku. Jeśli jednak chcesz odczytać oba pliki eof, musisz pracować z while'swymaganiami składni, tj. przez polecenie bezpośrednio przeddo while pętli wytwarzania niezerowy kod zwrotny, aby wydostać się z pętli while.
||
nie działa dla mnie Jest w stanie przetworzyć plik1 następnie file2 , ale robi zachować pliki zsynchronizowane z&&
, co wychodzi z while pętli podczas pierwszego EOF . - GNU bash 4.1.5||
„listy” zwiera jak w większości języków. Na pewno odpowiedziano na to tysiąc razy przed ...Gotowe; gotowe - potrzebujesz dwóch forów i dwóch dones:
Plik 2 jest oczywiście przetwarzany raz dla każdego słowa w pliku 1.
Użycie <zamiast kota powinno w większości przypadków być niezwykłym przyrostem wydajności.
Bez udziału podprocesu.(Niepewny co do ostatniego zdania).Nieskompresowane:
Jeśli nie lubisz czytać słów, ale wierszy i zachować białe znaki, użyj while i czytaj:
Jeśli chcesz dołączyć 2 pliki, a nie zagnieżdżać je:
Jeśli chcesz skompresować 2 pliki, użyj wklej:
źródło
<
porównaniecat
. Nie jestem pewien, jak go przetestować i kiedy stanie się on semantycznie ważny. Jeśli wywoływane są potoki, zmienne w podprocesach nie pojawiają się w głównym procesie, ale nie mamy tutaj zmiennych. Przekreślam zdanie krytyczne, dopóki ktoś nie może go wyjaśnić.while
ma interesującą składnię. Możesz umieścić wiele poleceń przeddo ... while
pętlą, a sprawa może wymagać żonglowania tą funkcją, w zależności od twoich szczególnych wymagań: czytasz do końca najdłuższego pliku, czy tylko do końca najkrótszego.Na przykład
read || read
po prostu nie działa (zgodnie z wymaganiami pytania), ponieważ gdy czytany jest pierwszy pliktrue
, odczyt drugiego pliku jest pomijany, dopóki pierwszy plik nie zostanie odczytany od początku do końca ... Wtedy, ponieważ status jest nadaltrue
, pętla while trwa i odczytuje drugi plik od początku do końca.read && read
odczyta pliki jednocześnie (synchronicznie), jeśli chcesz tylko czytać do najkrótszego pliku. Jeśli jednak chcesz odczytać oba plikieof
, musisz pracować zwhile's
wymaganiami składni, tj. przez polecenie bezpośrednio przeddo while
pętli wytwarzania niezerowy kod zwrotny, aby wydostać się z pętli while.Oto przykład, jak czytać oba pliki do eof
(możesz chcieć przetestować eof3 i eof4 przed odczytem, ale ogólna idea istnieje, szczególnie w końcowym stanie prawda / fałsz.
źródło