W poniższym programie, jeśli ustawię zmienną $foo
na wartość 1 w pierwszej if
instrukcji, działa ona w tym sensie, że jej wartość jest zapamiętywana po instrukcji if. Jednak gdy ustawię tę samą zmienną na wartość 2 wewnątrz instrukcji, if
która jest wewnątrz while
instrukcji, jest ona zapominana po while
pętli. Zachowuje się tak, jakbym używał jakiejś kopii zmiennej $foo
wewnątrz while
pętli i modyfikuję tylko tę konkretną kopię. Oto pełny program testowy:
#!/bin/bash
set -e
set -u
foo=0
bar="hello"
if [[ "$bar" == "hello" ]]
then
foo=1
echo "Setting \$foo to 1: $foo"
fi
echo "Variable \$foo after if statement: $foo"
lines="first line\nsecond line\nthird line"
echo -e $lines | while read line
do
if [[ "$line" == "second line" ]]
then
foo=2
echo "Variable \$foo updated to $foo inside if inside while loop"
fi
echo "Value of \$foo in while loop body: $foo"
done
echo "Variable \$foo after while loop: $foo"
# Output:
# $ ./testbash.sh
# Setting $foo to 1: 1
# Variable $foo after if statement: 1
# Value of $foo in while loop body: 1
# Variable $foo updated to 2 inside if inside while loop
# Value of $foo in while loop body: 2
# Value of $foo in while loop body: 2
# Variable $foo after while loop: 1
# bash --version
# GNU bash, version 4.1.10(4)-release (i686-pc-cygwin)
bash
while-loop
scope
sh
Eric Lilja
źródło
źródło
SC2030: Modification of foo is local (to subshell caused by pipeline).
Odpowiedzi:
while
Pętla wykonywana jest w podpowłoce. Tak więc wszelkie zmiany wprowadzone w zmiennej nie będą dostępne po wyjściu podpowłoki.Zamiast tego możesz użyć ciągu tutaj, aby ponownie napisać pętlę while, aby być w głównym procesie powłoki;
echo -e $lines
będzie działał tylko w podpowłoce:Możesz pozbyć się raczej brzydkiego
echo
z powyższego ciągu, rozszerzając sekwencje odwrotnego ukośnika natychmiast po przypisaniulines
.$'...'
Forma cytowania mogą być stosowane tam:źródło
<<< "$(echo -e "$lines")"
na prosty<<< "$lines"
tail -f
zamiast stałego tekstu?while read -r line; do echo "LINE: $line"; done < <(tail -f file)
(oczywiście pętla nie kończy się, ponieważ nadal czeka na dane wejściowetail
).while
pętli lubfor
pętli; raczej użycie podpowłoki, tj. wcmd1 | cmd2
,cmd2
jest w podpowłoce. Więc jeślifor
pętla jest wykonywana w podpowłoce, zostanie pokazane nieoczekiwane / problematyczne zachowanie.ZAKTUALIZOWANO # 2
Wyjaśnienie znajduje się w odpowiedzi Blue Moons.
Alternatywne rozwiązania:
Wyeliminować
echo
Dodaj echo do dokumentu tutaj jest
Uruchom
echo
w tle:Przekieruj jawnie do uchwytu pliku (Uwaga na miejsce
< <
!):Lub po prostu przekieruj do
stdin
:I jeden za
chepner
(eliminowanieecho
):Zmienna
$lines
może zostać przekonwertowana na tablicę bez uruchamiania nowej podpowłoki. Znaki\
in
należy przekonwertować na jakiś znak (np. Prawdziwy nowy znak linii) i użyć zmiennej IFS (Internal Field Separator) do podzielenia łańcucha na elementy tablicy. Można to zrobić w następujący sposób:Wynik jest
źródło
lines
wydaje się, że jedynym celem zmiennej jest zasileniewhile
pętli.for line in $(echo -e $lines); do ... done
Jesteś 742342. użytkownikiem, który zadaje to bash FAQ. Odpowiedź opisuje również ogólny przypadek zmiennych ustawionych w podpowłokach utworzonych przez potoki:
źródło
Hmmm ... prawie przysiągłbym, że to zadziałało dla oryginalnej powłoki Bourne'a, ale nie mam teraz dostępu do działającej kopii, aby to sprawdzić.
Istnieje jednak bardzo trywialne obejście tego problemu.
Zmień pierwszy wiersz skryptu z:
do
Zrobione! Odczyt na końcu potoku działa dobrze, zakładając, że masz zainstalowaną powłokę Korna.
źródło
A może bardzo prosta metoda
źródło
To interesujące pytanie dotyczy bardzo podstawowej koncepcji powłoki i podpowłoki Bourne'a. Tutaj zapewniam rozwiązanie, które różni się od poprzednich rozwiązań, wykonując pewnego rodzaju filtrowanie. Podam przykład, który może być przydatny w prawdziwym życiu. Jest to fragment do sprawdzania, czy pobrane pliki są zgodne ze znaną sumą kontrolną. Plik sumy kontrolnej wygląda następująco (pokazuje tylko 3 linie):
Skrypt powłoki:
Jednostka nadrzędna i podpowłoka komunikują się za pomocą polecenia echo. Możesz wybrać łatwy do przeanalizowania tekst dla powłoki nadrzędnej. Ta metoda nie łamie twojego normalnego sposobu myślenia, wystarczy, że będziesz musiał wykonać pewne przetwarzanie końcowe. Możesz do tego użyć grep, sed, awk i innych.
źródło