Szukam podstawowej pętli takiej jak:
for(int i = 0; i < MAX; i++) {
doSomething(i);
}
ale dla bash.
Szukam podstawowej pętli takiej jak:
for(int i = 0; i < MAX; i++) {
doSomething(i);
}
ale dla bash.
Odpowiedzi:
Z tej strony :
for i in $(seq 1 10);
do
echo $i
done
for ((i = 0 ; i < max ; i++ )); do echo "$i"; done
ArrayLength=${#array[@]}
jak jej tutaj używamy zamiast max
?
Bash for
składa się ze zmiennej (iteratora) i listy słów, w których iterator będzie iterował.
Jeśli więc masz ograniczoną listę słów, po prostu umieść je w następującej składni:
for w in word1 word2 word3
do
doSomething($w)
done
Prawdopodobnie chcesz iterować po niektórych liczbach, więc możesz użyć seq
polecenia, aby wygenerować dla siebie listę liczb: (na przykład od 1 do 100)
seq 1 100
i użyj go w pętli FOR:
for n in $(seq 1 100)
do
doSomething($n)
done
Zwróć uwagę na $(...)
składnię. Jest to zachowanie basha, pozwala na przekazanie danych wyjściowych z jednego polecenia (w naszym przypadku od seq
) do innego ( for
)
Jest to naprawdę przydatne, gdy musisz iterować po wszystkich katalogach w jakiejś ścieżce, na przykład:
for d in $(find $somepath -type d)
do
doSomething($d)
done
Możliwości generowania list są nieskończone.
Bash 3.0+ może używać tej składni:
for i in {1..10} ; do ... ; done
.. który pozwala uniknąć tworzenia zewnętrznego programu w celu rozszerzenia sekwencji (na przykład seq 1 10
).
Oczywiście ma to ten sam problem, co for(())
rozwiązanie, przywiązanie do basha, a nawet do konkretnej wersji (jeśli to dla ciebie ważne).
Wypróbuj bash
wbudowaną pomoc:
$ help for
for: for NAME [in WORDS ... ;] do COMMANDS; done
The `for' loop executes a sequence of commands for each member in a
list of items. If `in WORDS ...;' is not present, then `in "$@"' is
assumed. For each element in WORDS, NAME is set to that element, and
the COMMANDS are executed.
for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done
Equivalent to
(( EXP1 ))
while (( EXP2 )); do
COMMANDS
(( EXP3 ))
done
EXP1, EXP2, and EXP3 are arithmetic expressions. If any expression is
omitted, it behaves as if it evaluates to 1.
#! /bin/bash
function do_something {
echo value=${1}
}
MAX=4
for (( i=0; i<MAX; i++ )) ; {
do_something ${i}
}
Oto przykład, który może działać również w starszych powłokach, ale nadal jest wydajny w przypadku dużych zliczeń:
Z=$(date) awk 'BEGIN { for ( i=0; i<4; i++ ) { print i,"hello",ENVIRON["Z"]; } }'
Ale powodzenia w robieniu przydatnych rzeczy wewnątrz awk
: Jak używać zmiennych powłoki w skrypcie awk?
do
/ done
.
Zwykle lubię używać niewielkiego wariantu standardu pętli for. Często używam tego do uruchamiania poleceń na szeregu zdalnych hostów. Korzystam z rozwijania nawiasów klamrowych basha do tworzenia pętli for, które pozwalają mi tworzyć nienumeryczne pętle for.
Przykład:
Chcę uruchomić polecenie uptime na hostach frontendu 1-5 i hostach backendu 1-3:
% for host in {frontend{1..5},backend{1..3}}.mycompany.com
do ssh $host "echo -n $host; uptime"
done
Zwykle uruchamiam to jako jednowierszowe polecenie ze średnikami na końcach wierszy zamiast bardziej czytelnej wersji powyżej. Kluczową kwestią dotyczącą użycia jest to, że nawiasy klamrowe pozwalają na określenie wielu wartości, które mają być wstawione do ciągu (np. Pre {foo, bar} wyniki w prefoopost, prebarpost) i pozwalają zliczać / sekwencje przy użyciu podwójnych kropek (możesz użyć. .z itp.). Jednak składnia z dwoma kropkami jest nową funkcją bash 3.0; wcześniejsze wersje tego nie obsługują.
jeśli interesuje Cię tylko bash, to rozwiązanie "for ((...))" przedstawione powyżej jest najlepsze, ale jeśli chcesz czegoś zgodnego z POSIX SH, co będzie działać na wszystkich unikach, będziesz musiał użyć "expr" i „while”, a to dlatego, że „(())”, „seq” lub „i = i + 1” nie są tak przenośne między różnymi powłokami
Cały czas używam odmian tego do przetwarzania plików ...
dla plików w * .log; do echo "Rób rzeczy z: $ plikami"; echo "Rób więcej z: $ files"; Gotowe;
Jeśli interesuje Cię przetwarzanie list plików, spójrz na opcję -execdir dotyczącą plików .