Apa praktik terbaik untuk mewakili nilai boolean dalam skrip shell?

15

Saya tahu, bahwa ada nilai boolean di dalamnya bash, tetapi saya tidak pernah melihatnya digunakan di mana pun.

Saya ingin menulis pembungkus untuk beberapa informasi yang sering dicari di mesin saya, misalnya, apakah USB drive ini dimasukkan / dipasang.

Apa yang akan menjadi praktik terbaik untuk mencapai itu?

  • Sebuah benang?

    drive_xyz_available=true
  • Angka (0 untuk benar, ≠ 0 untuk salah)?

    drive_xyz_available=0    # evaluates to true
  • Sebuah fungsi?

    drive_xyz_available() { 
        if available_magic; then 
                return 0 
        else 
                return 1 
        fi
    }

Saya kebanyakan bertanya-tanya tentang, apa yang diharapkan oleh orang lain yang ingin menggunakan bungkusnya. Apakah mereka mengharapkan nilai boolean, perintah seperti variabel atau fungsi untuk dipanggil?

Dari sudut pandang keamanan saya akan berpikir opsi kedua adalah yang paling aman, tetapi saya akan senang mendengar pengalaman Anda.

Minix
sumber
3
help true ; help false ; help exit
Costas
3
@ Costas Apakah Anda keberatan menguraikan?
Minix

Jawaban:

2
bool(){ return "$((!${#1}))"; }

if bool "$var"
then : do true
else : do false

Hanya mengatur variabel untuk apa pun tetapi tidak-nol untuk bekerja di atas, meskipun [ -n "$var" ]akan lebih pendek, jika tidak sejelas itu.

Secara umum ketika skrip menginterpretasikan variabel lingkungan menjadi benar atau salah, itu akan menafsirkan nilai apa pun menjadi benar (dan kadang-kadang menggunakan nilai tersebut untuk mengkonfigurasi beberapa opsi) atau nilai nol sebagai salah.

Di atas mengembalikan nilai boolean !notdari len argumen pertama - jika argumen berisi sejumlah karakter selain 0 mengembalikan 0, jika tidak, tidak ada karakter sama sekali, mengembalikan 1. Ini adalah tes yang sama yang dapat Anda lakukan dengan [ -n "$var" ], pada dasarnya , tetapi hanya membungkusnya dalam fungsi kecil bernama bool().

Ini biasanya cara kerja variabel flag . Sebagai contoh:

[ -d "$dir" ] || dir=

Di mana bagian lain dari sebuah skrip hanya perlu mencari nilai apa saja $diruntuk mengukur kegunaannya. Ini juga berguna untuk penggantian parameter - karena parameter dapat diperluas ke nilai default untuk diisi dengan yang kosong atau tidak disetel, tetapi sebaliknya akan diperluas ke nilai preset seperti ...

for set in yes ''
do echo "${set:-unset or null}"
done

... yang akan mencetak ...

yes
unset or null

Tentu saja, ini juga memungkinkan untuk melakukan yang sebaliknya :+tetapi itu hanya dapat memberikan Anda preset default atau tidak sama sekali, sedangkan form di atas dapat memberi Anda nilai atau nilai default.

Dan mengenai tiga pilihan - siapa pun bisa bekerja tergantung pada bagaimana Anda memilih untuk mengimplementasikannya. Pengembalian fungsi adalah pengujian-sendiri, tetapi, jika pengembalian itu perlu disimpan karena alasan apa pun, harus dimasukkan ke dalam variabel. Tergantung pada use case - apakah nilai boolean yang Anda inginkan untuk mengevaluasi tes sekali dan jenis selesai? Jika demikian, lakukan fungsinya, kalau tidak salah satu dari dua lainnya mungkin diperlukan.

mikeserv
sumber
1
Saya tidak berpikir Anda menjawab pertanyaan saya. Saya tidak bertanya bagaimana boolean dapat digunakan dalam skrip shell, tetapi cara apa yang paling umum dan akan diharapkan oleh pengguna lain. Jika pertanyaan saya tidak jelas, saya akan senang mengeditnya. Juga penjelasan singkat untuk apa jawaban Anda akan menyenangkan. Terima kasih.
Minix
@ Minx Ada yang lebih baik?
mikeserv
Saya biasanya menetapkan trueatau falseke variabel, Anda dapat melakukannyaif $variable; then ...
wurtel
@wurtel - yang bergantung pada default $IFS- dan jika nilai var mungkin berisi input pengguna apa pun, maka juga semoga sukses. Jika nilainya tidak diketahui untuk memulainya maka ada sedikit kebutuhan untuk mengujinya. Lebih aman yang bisa Anda lakukan if ${var:+":"} false; thensaat bekerja dengan nilai null / bukan null. Tapi itu jarang lebih berguna daripada[ -n "$var" ] &&
mikeserv
Jika saya memulai skrip saya dengan variable=falsedan kemudian mengaturnya menjadi benar sesuai dengan kondisi apa pun (seperti yang saya lakukan ketika menggunakan variabel dalam C) maka tidak ada masalah apa pun, Apa obsesi Anda dengan berbagai nilai IFS dan nilai variabel acak dll. .
wurtel
4

Dalam bashsetiap variabel pada dasarnya adalah string (atau array atau fungsi, tetapi mari kita bicara tentang variabel reguler di sini).

Kondisi diuraikan berdasarkan nilai kembali dari perintah tes - nilai kembali bukan variabel, ini adalah kondisi keluar. Ketika Anda mengevaluasi if [ ... ]atau if [[ ]]atauif grep something sesuatu seperti itu, nilai balik 0 (bukan string 0, tetapi status keluar 0 = sukses) berarti benar dan sisanya berarti salah (jadi, kebalikan dari apa yang Anda gunakan dalam bahasa pemrograman yang dikompilasi, tetapi karena ada satu cara untuk berhasil dan banyak cara untuk gagal, dan hasil yang diharapkan dari eksekusi biasanya sukses, 0 digunakan sebagai hasil standar yang paling umum jika tidak ada yang salah). Ini sangat berguna karena setiap biner dapat digunakan sebagai tes - jika gagal, itu salah, jika tidak maka itu benar.

truedan falseprogram (biasanya ditimpa oleh builtin) hanya berguna program kecil yang tidak melakukan apa pun - trueberhasil melakukan apa-apa, dan keluar dengan 0, sementara falsemencoba melakukan apa-apa dan "gagal", keluar dengan 1. Kedengarannya tidak ada gunanya tetapi sangat berguna untuk skrip.

Adapun cara menyebarkan kebenaran di sekitar, terserah Anda. Sangat umum untuk hanya menggunakan "y" atau "ya" untuk kebenaran dan penggunaan if [ x"$variable" = x"yes" ](ditambahkan string dummy xkarena jika $variablekebetulan panjangnya nol, ini melindungi dari membuat perintah palsu if [ = "yes" ]yang tidak menguraikan). Mungkin juga berguna untuk hanya menggunakan string kosong untuk false, dan gunakan [ -z "$variable ]untuk menguji apakah panjangnya nol (atau -ntidak nol).

Pokoknya, sangat jarang untuk benar-benar harus melewati nilai-nilai boolean bash- itu jauh lebih umum untuk hanya exitpada kegagalan, atau mengembalikan hasil yang bermanfaat (atau nol jika ada masalah, dan menguji untuk string kosong), dan sebagian besar kasus dapat tes untuk kegagalan langsung dari status keluar.


Dalam kasus Anda, Anda menginginkan fungsi yang akan bertindak sebagai perintah lain (karena itu, kembalikan 0 pada kesuksesan), sehingga opsi terakhir Anda tampaknya merupakan pilihan yang tepat.

Juga, Anda bahkan mungkin tidak perlu returnpernyataan. Jika fungsinya cukup sederhana, Anda dapat menggunakan fakta bahwa itu hanya mengembalikan status dari perintah yang dieksekusi terakhir dalam fungsi. Jadi fungsi Anda bisa saja

drive_xyz_available() {
   [ -e /dev/disk/by-uuid/whatever ]
}

jika Anda menguji keberadaan node perangkat (atau grep /proc/mountsuntuk memeriksa apakah itu sudah terpasang?).

orion
sumber
Itu ringkasan yang sangat bagus, terima kasih telah meluangkan waktu untuk menuliskannya. Dapatkah saya menyimpulkan dari paragraf terakhir Anda, bahwa Anda akan mempertimbangkan pilihan drive_xyz_available()untuk menjadi yang paling umum?
Minix
Bisakah Anda memberikan beberapa contoh untuk y = truekasus umum ? Dalam pengalaman saya, sebagian besar skrip wrapper menguji untuk setiap nilai bukan nol untuk menganggapnya benar - setidaknya terkait variabel lingkungan yang ditafsirkan. Kalau tidak, mereka mengabaikan mobil shell sama sekali.
mikeserv
3
String boneka untuk iftes tidak perlu jika variabelnya dikutip; if [ "$variable" = "yes" ]berfungsi dengan baik bahkan jika $ variabel tidak disetel.
daniel kullmann
-2

Pada dasarnya angka apa pun yang bukan 0 adalah benar, dan 0 salah. Alasan untuk mengembalikan nilai sebagai 0 untuk akhir script yang sukses atau angka lainnya untuk mengidentifikasi berbagai jenis kesalahan.

$? akan mengembalikan kode keluar dari perintah sebelumnya / yang dapat dieksekusi, menjadi 0 berhasil dan angka lainnya kesalahan yang telah dikembalikan.

Jadi saya akan menggunakan metode itu untuk true / false. if (( ! $? ));then OK;else NOOK;fi

YoMismo
sumber
Saya akan menulis satu untuk opsi terakhir, kalau begitu. Terima kasih.
Minix
5
Angka bukan nol sebenarnya salah, dan nol benar. Lihat saja output dari true; echo $?dan false; echo $?.
Ruslan
@Ruslan. Apakah Anda memeriksa output dari perintah saya? Saya kira Anda tidak, jika tidak, Anda tidak akan menyatakan apa yang Anda lakukan. 0 salah, angka lainnya benar, alasan untuk meniadakan !hasilnya agar BENAR. Hasil dari suatu perintah adalah 0 ketika telah selesai dengan benar, yang tidak berarti 0 benar. Kata itu truemungkin 0, tetapi 0 tidak pernah benar seperti yang ifditunjukkan oleh kondisi.
YoMismo
Itu sama dengan mengatakan bahwa di C / C ++, 0adalah truekarena if(!x){True();}else{False();}akan memanggil True()kapan x==0. Tetapi cek yang benar bukan !x, melainkan !!x.
Ruslan
Kamu waaaaaayay salah. Saya tidak berbicara tentang apa dan urutan apa yang Anda tulis setelahif saya hanya menyatakan fakta bahwa di sini (dalam bash, atau ksh, atau tsh, atau ....) seperti dalam C / C ++ a 0 adalah FALSE, any nomor lainnya BENAR, seperti yang dapat Anda baca di tautan berikut, implementasi awal C tidak memberikan tipe boolean, yang didefinisikan sebagai int di mana 0 FALSE dan 1 TRUE en.wikipedia.org/wiki/Boolean_data_type .
YoMismo