Saya ingin mencoba skrip sederhana
flag=false
while !$flag
do
read x
if [ "$x" -eq "true" ]
then
flag=true
fi
echo "${x} : ${flag}"
done
Tetapi ketika saya menjalankannya, jika saya mengetik true
, saya akan melihat itu x="true"
dan flag="true"
, tetapi siklus tidak berakhir. Apa yang salah dengan skrip? Bagaimana saya bisa membalikkan variabel boolean dengan benar?
Jawaban:
Ada dua kesalahan dalam skrip Anda. Yang pertama adalah bahwa Anda memerlukan ruang di antara
!
dan$flag
, jika tidak, shell mencari perintah yang disebut!$flag
. Kesalahan kedua-eq
adalah untuk perbandingan integer, tetapi Anda menggunakannya pada string. Bergantung pada shell Anda, Anda akan melihat pesan kesalahan dan loop akan berlanjut selamanya karena kondisinya[ "$x" -eq "true" ]
tidak benar, atau setiap nilai non-integer akan diperlakukan sebagai 0 dan loop akan keluar jika Anda memasukkan string apa pun (termasukfalse
) selain angka yang berbeda dari 0.Meskipun
! $flag
benar, itu ide yang buruk untuk memperlakukan string sebagai perintah. Ini akan berhasil, tetapi akan sangat sensitif terhadap perubahan pada skrip Anda, karena Anda harus memastikan bahwa itu$flag
tidak akan menjadi apa pun kecualitrue
ataufalse
. Akan lebih baik menggunakan perbandingan string di sini, seperti dalam tes di bawah ini.Mungkin ada cara yang lebih baik untuk mengekspresikan logika yang Anda cari. Misalnya, Anda bisa membuat loop tak terbatas dan mematahkannya ketika Anda mendeteksi kondisi terminasi.
sumber
[
builtin ofksh
,[ x -eq y ]
mengembalikan true jikax
ekspresi aritmatika diselesaikan ke nomor yang sama dengany
ekspresi aritmatika jadi misalnyax=2 true=1+1 ksh -c '[ x -eq true ] && echo yes'
akan menampilkan ya.Meskipun tidak ada variabel Boolean di Bash, sangat mudah untuk meniru mereka menggunakan evaluasi aritmatika.
Ini juga berfungsi di ksh. Saya tidak akan terkejut jika bekerja di semua shell yang sesuai dengan POSIX, tetapi belum memeriksa standarnya.
sumber
! ! ((val))
berfungsi di Bash, seperti di C atau C ++? Misalnya, jikaval
0 tetap 0 setelah! !
. Jikaval
1 tetap 1 setelah! !
. Jikaval
8 maka ditarik ke 1 setelah! !
. Atau apakah saya perlu mengajukan pertanyaan lain?Jika Anda dapat benar-benar yakin bahwa variabel tersebut akan berisi 0 atau 1, Anda dapat menggunakan operator bitwise XOR untuk membalik di antara dua nilai:
sumber
Ini bekerja untuk saya:
Tapi, sebenarnya, yang harus Anda lakukan adalah mengganti
while
dengan:sumber
Tidak ada konsep variabel boolean di shell.
Variabel shell hanya bisa
text
(string), dan, dalam beberapa kasus, teks yang dapat ditafsirkan sebagai integer (1
,0xa
,010
, dll).Karena itu, a
flag=true
tidak menyiratkan kebenaran atau kepalsuan pada cangkang sama sekali.Tali
Apa yang bisa dilakukan adalah perbandingan string
[ "$flag" == "true" ]
atau menggunakan konten variabel dalam beberapa perintah dan memeriksa konsekuensinya , seperti mengeksekusitrue
(karena ada keduanya dieksekusi dipanggiltrue
dan satu dipanggilfalse
) sebagai perintah dan periksa apakah kode keluar dari perintah itu nol (berhasil).Atau lebih pendek:
Jika konten variabel digunakan sebagai perintah, a
!
dapat digunakan untuk meniadakan status keluar dari perintah, jika ada spasi di antara keduanya (! cmd
), seperti pada:Skrip harus berubah menjadi:
Bilangan bulat
Gunakan nilai numerik dan Ekspansi Aritmatika .
Dalam hal ini, kode keluar
$((0))
is1
dan kode exit$((1))
is0
.Dalam bash, ksh dan zsh aritmatika dapat dilakukan di dalam
((..))
(perhatikan bahwa permulaan$
hilang).flag=0; if ((flag)); then ... fi
Versi portabel dari kode ini lebih berbelit-belit:
Di bash / ksh / zsh Anda bisa melakukan:
kalau tidak
Anda dapat "Membalikkan variabel boolean" (asalkan berisi nilai numerik) sebagai:
((flag=!flag))
Itu akan mengubah nilai
flag
menjadi0
atau1
.Catatan : Silakan periksa kesalahan di https://www.shellcheck.net/ sebelum memposting kode Anda sebagai pertanyaan, berkali-kali itu sudah cukup untuk menemukan masalah.
sumber
until
kependekan dariwhile !
(danuntil
, berlawanan dengan!
Bourne), sehingga Anda dapat melakukan:Yang harus sama dengan:
Anda juga dapat menuliskannya sebagai:
Bagian antara
until
/while
dando
tidak harus menjadi satu perintah.!
adalah kata kunci dalam sintaks POSIX shell. Ini perlu dibatasi, token yang terpisah dari yang mengikuti dan menjadi token pertama yang mendahului pipa (! foo | bar
meniadakan pipa danfoo | ! bar
tidak valid meskipun beberapa shell menerimanya sebagai perpanjangan).!true
ditafsirkan sebagai!true
perintah yang tidak mungkin ada.! true
harus bekerja.!(true)
harus bekerja di shell yang sesuai dengan POSIX seperti yang!
dibatasi karena diikuti oleh(
token, tetapi dalam praktiknya ia tidak bekerja diksh
/ dibash -O extglob
mana ia berkonflik dengan!(pattern)
operator glob yang diperluas atau zsh (kecuali dalam emulasi sh) di mana ia berkonflikglob(qualifiers)
denganbareglobqual
danglob(group)
tanpa.sumber
atau bahkan:
harus melakukan pekerjaan
sumber