Chcę wypróbować prosty skrypt
flag=false
while !$flag
do
read x
if [ "$x" -eq "true" ]
then
flag=true
fi
echo "${x} : ${flag}"
done
Ale kiedy go uruchomię, jeśli napiszę true
, zobaczę x="true"
i flag="true"
, ale cykl się nie kończy. Co jest nie tak ze skryptem? Jak poprawnie odwrócić zmienną boolowską?
Odpowiedzi:
W twoim skrypcie są dwa błędy. Pierwszym jest to, że potrzebujesz odstępu między
!
i$flag
, w przeciwnym razie powłoka szuka polecenia o nazwie!$flag
. Drugi błąd dotyczy-eq
porównań liczb całkowitych, ale używasz go w ciągu znaków. W zależności od powłoki albo zobaczysz komunikat o błędzie, a pętla będzie trwała wiecznie, ponieważ warunek[ "$x" -eq "true" ]
nie może być spełniony, lub każda wartość nie będąca liczbą całkowitą będzie traktowana jako 0, a pętla zakończy się, jeśli wpiszesz dowolny ciąg (w tymfalse
) inna niż liczba różna od 0.Chociaż
! $flag
jest poprawne, złym pomysłem jest traktowanie łańcucha jako polecenia. To by działało, ale byłoby bardzo wrażliwe na zmiany w twoim skrypcie, ponieważ musisz upewnić się, że$flag
nigdy nie będzie to nic innego jaktrue
lubfalse
. Lepiej byłoby użyć porównania ciągów tutaj, jak w poniższym teście.Prawdopodobnie istnieje lepszy sposób na wyrażenie logiki, której szukasz. Na przykład możesz utworzyć nieskończoną pętlę i przerwać ją, gdy wykryjesz warunek zakończenia.
źródło
[
wbudowanego polecenia zksh
,[ x -eq y ]
return true jeślix
arytmetycznych ustąpieniu ekspresyjnych do takiej samej liczby jakoy
wyrażenia arytmetycznego tak na przykładx=2 true=1+1 ksh -c '[ x -eq true ] && echo yes'
would Tak Wyjście.Chociaż w Bash nie ma zmiennych boolowskich, bardzo łatwo jest je emulować za pomocą obliczeń arytmetycznych.
Działa to również w ksh. Nie zdziwiłbym się, gdyby działał we wszystkich powłokach zgodnych z POSIX, ale nie sprawdził standardu.
źródło
! ! ((val))
działa w Bash, podobnie jak w C lub C ++? Na przykład, jeślival
jest 0, pozostaje 0 po! !
. Jeślival
jest 1, pozostaje 1 po! !
. Jeślival
ma wartość 8, jest zmniejszany do 1 po! !
. Czy muszę zadać kolejne pytanie?Jeśli możesz być absolutnie pewien, że zmienna będzie zawierać 0 lub 1, możesz użyć bitowego operatora XOR do przełączania między dwiema wartościami:
źródło
To działa dla mnie:
Ale tak naprawdę powinieneś zrobić to
while
:źródło
W powłoce nie ma koncepcji zmiennej boolowskiej.
Zmienne powłoki mogą być tylko
text
(ciągiem), a w niektórych przypadkach tekst ten może być interpretowany jako liczba całkowita (1
,0xa
,010
, itd.).Dlatego a
flag=true
nie sugeruje żadnej prawdziwości ani fałszu skorupie.Strunowy
To, co można zrobić, to albo porównać ciąg znaków,
[ "$flag" == "true" ]
albo użyć zawartości zmiennej w niektórych poleceniach i sprawdzić ich konsekwencje , na przykład wykonaćtrue
(ponieważ istnieje zarówno wywołany plik wykonywalny, jaktrue
i jeden wywołanyfalse
) jako polecenie i sprawdzić, czy kod wyjścia tego polecenia wynosi zero (odnoszący sukcesy).Lub krócej:
Jeśli zawartość zmiennej jest używana jako polecenie,
!
można użyć do negowania statusu wyjścia polecenia, jeśli między nimi (! cmd
) istnieje spacja , jak w:Skrypt powinien zmienić się na:
Liczba całkowita
Użyj wartości liczbowych i rozszerzeń arytmetycznych .
W takim przypadku kod wyjścia
$((0))
to1
i kod wyjścia$((1))
to0
.W bash, ksh i zsh arytmetyka może być przeprowadzona wewnątrz
((..))
(zauważ, że$
brakuje początku).flag=0; if ((flag)); then ... fi
Przenośna wersja tego kodu jest bardziej skomplikowana:
W bash / ksh / zsh możesz zrobić:
Alternatywnie
Możesz „Odwrócić zmienną logiczną” (pod warunkiem, że zawiera wartość liczbową) jako:
((flag=!flag))
To zmieni wartość
flag
na jedną0
lub1
.Uwaga : przed opublikowaniem kodu jako pytania sprawdź błędy w https://www.shellcheck.net/ , wiele razy to wystarczy, aby znaleźć problem.
źródło
until
jest skrótem odwhile !
(iuntil
, w przeciwieństwie do!
Bourne'a), więc możesz zrobić:Który powinien być taki sam jak:
Możesz również napisać to jako:
Część pomiędzy
until
/while
ido
nie musi być pojedynczym poleceniem.!
jest słowem kluczowym w składni powłoki POSIX. Należy go oddzielić, token oddzielić od tego, co następuje, i być pierwszym tokenem poprzedzającym potok (! foo | bar
neguje potok ifoo | ! bar
jest nieprawidłowy, chociaż niektóre powłoki akceptują go jako rozszerzenie).!true
jest interpretowane jako!true
polecenie, które prawdopodobnie nie istnieje.! true
powinno działać.!(true)
powinien działać w powłokach zgodnych z POSIX, ponieważ!
jest on ograniczony, ponieważ następuje po nim(
token, ale w praktyce nie działa wksh
/bash -O extglob
gdzie jest w konflikcie z!(pattern)
rozszerzonym operatorem glob ani zsh (z wyjątkiem emulacji sh), gdzie jest w konflikcieglob(qualifiers)
zbareglobqual
iglob(group)
bez.źródło
lub nawet:
powinien wykonać pracę
źródło