Penggunaan && dan || yang membingungkan operator

94

Saya membaca sekilas melalui /etc/rc.d/init.d/sendmailberkas (saya tahu ini adalah hampir tidak pernah digunakan, tapi aku belajar untuk ujian), dan aku sudah menjadi sedikit bingung tentang &&dan ||operator. Saya telah membaca di mana mereka dapat digunakan dalam pernyataan seperti:

if [ test1 ] && [ test2 ]; then
     echo "both tests are true"
elif [ test1 ] || [ test2 ]; then
     echo "one test is true"
fi

Namun, skrip ini menampilkan pernyataan garis tunggal seperti:

[ -z "$SMQUEUE" ] && SMQUEUE="QUEUE"
[ -f /usr/sbin/sendmail ] || exit 0

Ini tampaknya menggunakan &&dan ||operator untuk memperoleh tanggapan berdasarkan tes, tapi saya belum bisa menggali dokumentasi mengenai penggunaan khusus dari operator ini. Adakah yang bisa menjelaskan hal ini dalam konteks khusus ini?

josh-cain
sumber

Jawaban:

141

Sisi kanan &&hanya akan dievaluasi jika status keluar dari sisi kiri adalah nol (yaitu benar). ||adalah kebalikannya: ia akan mengevaluasi sisi kanan hanya jika status keluar sisi kiri adalah non-nol (yaitu salah).

Anda dapat mempertimbangkan [ ... ]untuk menjadi program dengan nilai pengembalian. Jika pengujian di dalam bernilai true, hasilnya nol; itu mengembalikan bukan nol sebaliknya.

Contoh:

$ false && echo howdy!

$ true && echo howdy!
howdy!
$ true || echo howdy!

$ false || echo howdy!
howdy!

Catatan tambahan:

Jika Anda melakukannya which [, Anda mungkin melihat bahwa [sebenarnya menunjuk ke suatu program! Tapi biasanya bukan yang berjalan dalam skrip; lari type [untuk melihat apa yang sebenarnya dijalankan. Jika Anda lemah untuk mencoba menggunakan program ini, hanya memberikan path lengkap seperti: /bin/[ 1 = 1.

Shawn J. Goff
sumber
6
Saat Anda melihat "X atau Y", Anda menguji X. Jika itu benar, Anda sudah tahu jawaban untuk "X atau Y" (itu benar), jadi tidak perlu menguji Y. Jika itu benar, Anda tidak tahu jawaban untuk "X atau Y", jadi Anda harus menguji Y. Ketika Anda melihat "X dan Y", Anda menguji X. Jika itu salah, Anda sudah tahu jawaban untuk "X dan Y" (itu salah), jadi tidak perlu menguji Y. Jika X benar, maka Anda perlu menguji Y untuk melihat apakah "X dan Y" benar.
David Schwartz
2
Alih-alih "jika sisi kiri mengembalikan nol", saya akan menulis "jika status keluar perintah sisi kiri adalah nol". Saya menemukan "kembali" agak ambigu karena output dan status keluar keduanya dapat dianggap sebagai "nilai kembali"
glenn jackman
Tidak hanya dapat Anda " mempertimbangkan [ ... ] untuk menjadi program", dalam banyak kasus adalah . Biasanya ada dalam file /bin/[atau /usr/bin/[.
LS
5
Pemrogram C akan merasa ini sangat membingungkan. Ada 0 berarti salah ... Sedangkan dalam shellscripting 0 berarti benar ... Mind blown.
Calmarius
Satu lagi yang bisa Anda sebutkan adalah testbukan ifatau [. Dan if [dan if testtampaknya diselingi dengan [dan testtanpa sajak atau alasan yang jelas. testmuncul pada kesempatan, seperti di config.site untuk lib vendor di Fedora x86_64 .
60

Inilah lembar contekan saya:

  • "A; B" Jalankan A dan kemudian B, terlepas dari keberhasilan A
  • "A&& B" Jalankan B jika A berhasil
  • "A || B" Jalankan B jika A gagal
  • "A &" Jalankan A di latar belakang.
pengguna177073
sumber
Ada beberapa paralel kalkulus lambda yang menarik yang ditunjukkan di sini dalam JavaScript yang berfungsi (tentukan variabel secara berurutan); "kiri (alias benar)": (a => b => a). "benar (alias palsu)": (a => b => b). "A; B" "lalu" (a => b => (() => b())(a())). "A && B" "jika tanpa yang lain (kapan)" (a => b => a()(() => right)(b)). "A || B" "lain tanpa if (kecuali)" (a => b => a()(b)(() => right)). "a && b || c" "ifThenElse" (a => b => c => (unless(when(a)(b))(c))()).
Dmitry
1
perhatikan bahwa dalam bash, kiri adalah analog 0 / string kosong, analog kanan adalah segalanya.
Dmitry
28

untuk memperluas jawaban @ Shawn-j-Goff dari atas, &&adalah logika AND, dan ||merupakan OR logis.

Lihat ini bagian dari Advanced Bash Scripting Guide. Beberapa konten dari tautan untuk referensi pengguna seperti di bawah ini.

&& DAN

if [ $condition1 ] && [ $condition2 ]
#  Same as:  if [ $condition1 -a $condition2 ]
#  Returns true if both condition1 and condition2 hold true...

if [[ $condition1 && $condition2 ]]    # Also works.
#  Note that && operator not permitted inside brackets
#+ of [ ... ] construct.

|| ATAU

if [ $condition1 ] || [ $condition2 ]
# Same as:  if [ $condition1 -o $condition2 ]
# Returns true if either condition1 or condition2 holds true...

if [[ $condition1 || $condition2 ]]    # Also works.
#  Note that || operator not permitted inside brackets
#+ of a [ ... ] construct.
Tim Kennedy
sumber
12

Dari pengalaman saya, saya menggunakan && dan || untuk mengurangi pernyataan if ke satu baris.

Katakanlah kita sedang mencari file bernama /root/Sample.txt maka iterasi tradisional akan seperti berikut dalam shell:

if [ -f /root/Sample.txt ]
then
    echo "file found"
else
    echo "file not found"
fi

6 baris ini dapat direduksi menjadi satu baris:

[[ -f /root/Sample.txt ]] && echo "file found" || echo "file not found"

Ketika menjalankan beberapa iterasi untuk mengatur variabel atau untuk membuat file dll., Hidup lebih mudah dan skrip terlihat lebih licin menggunakan satu baris jika berfungsi, itu hanya kekurangannya adalah menjadi sedikit lebih sulit untuk mengimplementasikan beberapa perintah dari satu iterasi. Anda dapat menggunakan berbagai fungsi.

syme89
sumber
Ini keren. Mengingatkan saya pada kode objc (a == b)? Val = 1: val = 2;
GeneCode
Bagaimana saya bisa menggunakan perintah ini ketika saya ingin menjalankan proses di latar belakang dengan "&"? Saya mendapatkan kesalahan sintaks untuk./someScript.sh & && echo 'ok' || echo 'ko'
Katie
4

Ada gagasan "jalan pintas".

Kapan (expr1 && expr2)dievaluasi - expr2hanya dievaluasi jika exp1dievaluasi ke "benar". Ini karena keduanya expr1DAN expr2harus benar untuk (expr1 && expr2)menjadi benar. Jika expr1dievaluasi menjadi "false" expr2TIDAK dievaluasi (jalan pintas) karena (expr1 && expr2)sudah "terbang".

Coba yang berikut - asumsikan file F1ada & file F2tidak ada:

( [ -s F1 ] && echo "File Exists" )  # will print "File Exists" - no short cut
( [ -s F2 ] && echo "File Exists" )  # will NOT print "File Exists" - short cut

Demikian pula untuk ||(atau) - tetapi jalan pintas terbalik.

Larry
sumber
5
Logikanya biasanya disebut sebagai "hubungan arus pendek". Saya belum pernah melihat frasa "jalan pintas" digunakan. Saya menyebutkan ini untuk membantu menemukan referensi.
LS
-1

Contoh-contoh dalam jawaban oleh Shawn J. Goff benar, tetapi penjelasannya sebaliknya. Silakan periksa:

Sisi kanan && hanya akan dievaluasi jika status keluar dari sisi kiri adalah NONZERO. || sebaliknya: ia akan mengevaluasi sisi kanan hanya jika status keluar sisi kiri adalah NOL.

Try2Help
sumber
3
Anda sadar bahwa untuk kode keluar nol shell bernilai true dan dengan demikian bukan kode keluar di sisi kiri &&hasil seluruh ekspresi untuk mengembalikan false ?
countermode
1
Seseorang tidak menyetujui editan Anda karena itu bukan jawaban Anda. Jika Anda berpikir bahwa beberapa jawaban salah, Anda harus menghapusnya dan mungkin meninggalkan komentar; jika Anda berpikir bahwa itu memerlukan perubahan, Anda harus meninggalkan komentar. Mengedit adalah untuk memperbaiki kesalahan tata bahasa, pemformatan, dan pengejaan yang tidak mengubah arti dari jawaban.
techraf
1
@countermode Maaf, Anda benar, saya pikir di Linux nol = false dan bukan nol = true (seperti di C dan banyak bahasa / lingkungan / platform lainnya). Saya minta maaf atas kesalahpahaman ini.
Try2Help