Boole değişkenini ters çevir


26

Basit script denemek istiyorum

flag=false
while !$flag
do
   read x
   if [ "$x" -eq "true" ]
   then
     flag=true
   fi
   echo "${x} : ${flag}"
done

Ama çalıştırdığımda true, yazarsam bunu göreceğim x="true"ve flag="true", ama döngü bitmiyor. Senaryoda yanlış olan ne? Boole değişkenini nasıl düzgün bir şekilde tersine çevirebilirim?



Teşekkürler! Şimdi anladım
İsveç

Yanıtlar:


21

Komut dosyanızda iki hata var. Bunlardan ilki !ve arasında bir boşluğa ihtiyacınız olması $flag, aksi takdirde kabuk denilen bir komutu arar !$flag. İkinci hata ise -eqtamsayı karşılaştırmaları içindir, fakat onu bir ipte kullanıyorsunuz. Kabuğunuza bağlı olarak, bir hata mesajı görürsünüz ve döngü sonsuza kadar devam eder, çünkü koşul [ "$x" -eq "true" ]doğru olamaz veya tamsayı olmayan her değer 0 olarak kabul edilir ve herhangi bir dize girerseniz döngüden çıkar.false ) 0'dan farklı bir sayı dışında

! $flagDoğru olsa da, bir dizgiyi komut olarak ele almak kötü bir fikirdir. İşe yarayacaktı ama betiğinizdeki değişikliklere karşı çok duyarlı olacaktı, çünkü ya $flagda hiçbir zaman olamayacağından emin olmanız gerekiyor . Burada testte olduğu gibi bir dizi karşılaştırması kullanmak daha iyi olacaktır.truefalse

flag=false
while [ "$flag" != "true" ]
do
   read x
   if [ "$x" = "true" ]
   then
     flag=true
   fi
   echo "${x} : ${flag}"
done

Muhtemelen peşinde olduğun mantığı ifade etmenin daha iyi bir yolu var. Örneğin, sınırsız bir döngü oluşturabilir ve sonlandırma koşulunu algıladığınızda bunu kırabilir.

while true; do
  read -r x
  if [ "$x" = "true" ]; then break; fi
  echo "$x: false"
done

İle [arasında yerleşiğini ksh, [ x -eq y ]eğer doğruysa dönmek xaritmetik ifade giderir aynı numaraya yböylece örneğin aritmetik ifade x=2 true=1+1 ksh -c '[ x -eq true ] && echo yes'çıktılayacaktır evet.
Stéphane Chazelas

10

Bash'de Boole değişkenleri bulunmamakla birlikte, aritmetik değerlendirme kullanarak bunları taklit etmek çok kolaydır.

flag= # False
flag=0 # False
flag=1 # True (actually any integer number != 0 will do, but see remark below about toggling)
flag="some string" # Maybe False (make sure that the string isn't interpreted as a number)

if ((flag)) # Test for True
then
  : # do something
fi

if ! ((flag)) # Test for False
then
  : # do something
fi

flag=$((1-flag)) # Toggle flag (only works when flag is either empty or unset, 0, 1, or a string which doesn't represent a number)

Bu aynı zamanda ksh ile de çalışır. POSIX uyumlu tüm mermilerde çalışırsa şaşırmam ama standardı kontrol etmedim.


1
! ! ((val))Bash'de, C veya C ++ 'da olduğu gibi çalışır mı ? Örneğin val, 0 ise , sonra 0 kalır ! !. val1 ise , sonra 1 kalır ! !. Eğer val8 o sonra 1'e aşağı çekilir ! !. Yoksa başka bir soru sormam gerekiyor mu?

1
-1 | POSIX sh'de bağımsız ((..)) tanımsızdır; lütfen referansı kaldırın
LinuxSecurityFreak

Vlastimil soru özellikle bash hakkında - posix kabuk hakkında. Soru bu konuyla ilgili olmadığında neden aşağı oy?
Nick Bull

6

Değişkenin 0 veya 1 içerdiğinden kesinlikle emin olabilirseniz, iki değer arasında geçiş yapmak için bit yönünde XOR'ye eşit operatörü kullanabilirsiniz:

$ foo=0
$ echo $foo
0
$ ((foo ^= 1))
$ echo $foo
1
$ ((foo ^= 1))
$echo $foo
0

2

Bu benim için çalışıyor:

flag=false
while [[ "$flag" == "false" ]]
do
   read x
   if [[ "$x" == "true" ]]
   then
     flag=true
   fi
   echo "${x} : ${flag}"
done

Fakat aslında, yapmanız gereken şey whileşununla değiştirmektir :

while ! $flag

0

Kabukta bir boole değişkeni kavramı yoktur.
Kabuk değişkenleri yalnızca olabilir text((bir dize) ve bazı durumlarda, bu metin bir tamsayı olarak yorumlanabilir 1, 0xa,010 vb.)

Bu nedenle, bir flag=true kabuk hiçbir şekilde doğruluk veya yanlışlık anlamına gelmez.

sicim

Ne yapılabilirdi ya bir dize karşılaştırma [ "$flag" == "true" ]ya da bazı komut değişken içeriği kullanın ve check sonuçlarını yürütmek gibi true(her ikisi de yürütülebilir bir adlandırılan olduğundan trueve bir adlandırılan falsebu komutun çıkış kodu sıfır ise) komut olarak ve check (başarılı).

$flag; if [ "$?" -eq 0 ]; then ... fi

Veya daha kısa:

if "$flag"; then ... fi

Bir değişkenin içeriği bir komut !olarak kullanılıyorsa, komutun çıkış durumunu olumsuzlamak için bir komut kullanılabilir: eğer her ikisi de arasında boşluk varsa ! cmd:

if ! "$flag"; then ... fi

Komut dosyası şöyle değişmeli:

flag=false
while ! "$flag" 
do
   read x
   if [ "$x" == "true" ]
   then
     flag=true
   fi
   echo "${x} : ${flag}"
done

tamsayı

Sayısal değerler ve Aritmetik Genişlemeler kullanın .

Bu durumda, çıkış kodu $((0))IS 1ve çıkış kodu $((1))olan 0.
Bash, ksh ve zsh aritmetiği bir içinde gerçekleştirilebilir ((..))(başlangıç $eksik olduğuna dikkat edin ).

flag=0; if ((flag)); then ... fi

Bu kodun taşınabilir bir sürümü daha karmaşıktır:

flag=0; if [ "$((flag))" -eq 0 ]; then ... fi      # test for a number
flag=0; if [ "$((flag))"  == 0 ]; then ... fi      # test for the string "0"

Bash / ksh / zsh içinde yapabilecekleriniz:

flag=0    
while ((!flag)) 
do
   read x
   [ "$x" == "true" ] && flag=1
   echo "${x} : ${flag}"
done

alternatif olarak

"Boolean değişkenini ters çevir" ifadesini (sayısal bir değer içermesi koşuluyla):

((flag=!flag))

Bu ya da değerini değiştirecek .flag01


Not : Lütfen kodunuzu bir soru olarak göndermeden önce, sorunu bulmak için yeterli olan birçok kez https://www.shellcheck.net/ adresindeki hataları kontrol edin .


0

untilkısacası while !(ve Bourne'un untilaksine !), yani:

flag=false
until "$flag"
do
   IFS= read -r x
   if [ "$x" = true ]
   then
     flag=true
   fi
   printf '%s\n' "$x : $flag"
done

Hangi aynı olmalıdır:

flag=false
while ! "$flag"
do
   IFS= read -r x
   if [ "$x" = true ]
   then
     flag=true
   fi
   printf '%s\n' "$x : $flag"
done

Ayrıca şunu da yazabilirsiniz:

until
   IFS= read -r x
   printf '%s\n' "$x"
   [ "$x" = true ]
do
   continue
done

Arasındaki kısım until/ ' whileve dotek bir komut olmak zorunda değildir.

!POSIX kabuk sözdiziminde bir anahtar kelimedir. Bu bir belirteç takip eder ve bir boru hattı öncesinde (ilk belirteci olmak ne ayrılmış ayrılmış gereken ! foo | barolumsuzlar boru hattı ve foo | ! barbazı kabukları bir uzantısı olarak kabul olsa geçersizdir).

!true!truevar olması muhtemel olmayan komut olarak yorumlanır . ! trueçalışmalı. !(true)bu kadar POSIX uyumlu kabuklarda çalışmalıdır !bir takip ediyor olarak sınırlandırılmış olan (jeton, ama pratikte iş yapmaz ksh/ bash -O extglobo çelişen nerede!(pattern) o çelişen nerede (sh öykünmesi hariç) genişletilmiş glob operatörü ne de zsh glob(qualifiers)ile bareglobqualve glob(group)olmadan.


-1
[ ${FOO:-0} == 0 ] && FOO=1 || FOO=0

ya da:

[ ${FOO:-false} == false ] && FOO=true || FOO=false

işi yapmalı

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.