Việc sử dụng nhầm lẫn giữa && và || khai thác


93

Tôi đã lướt qua một /etc/rc.d/init.d/sendmailtập tin (tôi biết rằng nó hầu như không bao giờ được sử dụng, nhưng tôi đang học để kiểm tra), và tôi đã có một chút bối rối về &&các ||nhà khai thác và. Tôi đã đọc nơi chúng có thể được sử dụng trong các tuyên bố như:

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

Tuy nhiên, tập lệnh này hiển thị các câu lệnh đơn như:

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

Chúng dường như đang sử dụng các toán tử &&||toán tử để gợi ra các câu trả lời dựa trên các bài kiểm tra, nhưng tôi chưa thể khai thác được sự hiểu biết về việc sử dụng cụ thể các toán tử này. Bất cứ ai có thể giải thích những gì làm trong bối cảnh cụ thể này?

Câu trả lời:


141

Phía bên phải của &&sẽ chỉ được đánh giá nếu trạng thái thoát của bên trái bằng không (nghĩa là đúng). ||là ngược lại: nó sẽ đánh giá phía bên phải chỉ khi trạng thái thoát bên trái là khác không (tức là sai).

Bạn có thể coi [ ... ]là một chương trình có giá trị trả về. Nếu thử nghiệm bên trong đánh giá là đúng, nó trả về 0; nó trả về khác không.

Ví dụ:

$ false && echo howdy!

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

$ false || echo howdy!
howdy!

Ghi chú thêm:

Nếu bạn làm như vậy which [, bạn có thể thấy rằng [thực sự chỉ đến một chương trình! Tuy nhiên, đó thường không phải là chương trình chạy trong các tập lệnh; chạy type [để xem những gì thực sự được chạy. Nếu bạn muốn thử sử dụng chương trình, chỉ cần đưa ra đường dẫn đầy đủ như vậy : /bin/[ 1 = 1.


6
Khi bạn thấy "X hoặc Y", bạn kiểm tra X. Nếu đó là sự thật, bạn đã biết câu trả lời cho "X hoặc Y" (đó là sự thật), vì vậy không cần phải kiểm tra Y. Nếu đó là sự thật, bạn không biết trả lời "X hoặc Y", vì vậy bạn cần kiểm tra Y. Khi bạn thấy "X và Y", bạn kiểm tra X. Nếu đó là sai, bạn đã biết câu trả lời cho "X và Y" (đó là sai), vì vậy, sai không cần kiểm tra Y. Nếu X là đúng, thì bạn cần phải kiểm tra Y để xem "X và Y" có đúng không.
David Schwartz

2
Thay vì "nếu bên trái trả về 0", tôi sẽ viết "nếu trạng thái thoát lệnh của bên trái bằng không". Tôi thấy "return" hơi mơ hồ vì đầu ra và trạng thái thoát đều có thể được coi là "giá trị trả về"
glenn jackman

Bạn không chỉ có thể " coi [ ... ] là một chương trình", trong nhiều trường hợp là như vậy . Nó thường có trong tập tin /bin/[hoặc /usr/bin/[.
LS

5
Lập trình viên C sẽ thấy điều này siêu khó hiểu. Có 0 có nghĩa là sai ... Trong khi trong shellscripting 0 có nghĩa là đúng ... Tâm trí bị thổi bay.
Calmarius

Một số khác mà bạn có thể đề cập là testthay vì ifhoặc [. Và if [if testdường như được xen kẽ với [testkhông có vần điệu rõ ràng hoặc lý do. testthỉnh thoảng xuất hiện, như tại config.site cho libs của nhà cung cấp trên Fedora x86_64 .

59

Đây là bảng cheat của tôi:

  • "A; B" Chạy A và sau đó B, bất kể thành công của A
  • "A && B" Chạy B nếu A thành công
  • "A || B" Chạy B nếu A thất bại
  • "A &" Chạy A trong nền.

Có một số phép tính lambda thú vị tương tự đang diễn ra ở đây được thể hiện trong JavaScript hoạt động (xác định các biến theo thứ tự); "Trái (aka đúng)" : (a => b => a). "đúng (còn gọi là sai)" : (a => b => b). "A; B" "rồi" (a => b => (() => b())(a())). "A && B" "nếu không có (khi)" (a => b => a()(() => right)(b)). "A | | B" "khác mà không có (trừ khi)" (a => b => a()(b)(() => right)). "a && b || c" "ifThenElse" (a => b => c => (unless(when(a)(b))(c))()).
Dmitry

1
lưu ý rằng trong bash, bên trái là tương tự 0 / chuỗi rỗng, bên phải tương tự là mọi thứ khác.
Dmitry

28

để mở rộng câu trả lời của @ Shawn-j-Goff từ trên xuống, &&là logic VÀ và ||là logic HOẶC.

Xem phần này của Hướng dẫn lập trình Bash nâng cao. Một số nội dung từ liên kết để người dùng tham khảo như dưới đây.

&& VÀ

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.

| | HOẶC LÀ

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.

11

Từ kinh nghiệm của mình, tôi sử dụng && và || để giảm một câu lệnh if thành một dòng duy nhất.

Giả sử chúng tôi đang tìm kiếm một tệp có tên /root/Sample.txt thì phép lặp truyền thống sẽ như sau trong shell:

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

6 dòng này có thể được giảm xuống thành một dòng duy nhất:

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

Khi chạy một vài lần lặp để đặt biến hoặc để tạo tệp, v.v., cuộc sống sẽ dễ dàng hơn và tập lệnh trông trơn tru hơn khi sử dụng một dòng if, chức năng chỉ là khó khăn hơn khi thực hiện nhiều lệnh từ một lần lặp duy nhất bạn có thể sử dụng các chức năng.


Điều này thật tuyệt Nhắc tôi về mã objc (a == b)? Val = 1: val = 2;
GeneCode

Làm cách nào tôi có thể sử dụng lệnh này khi tôi muốn chạy một tiến trình trong nền với "&"? Tôi gặp lỗi cú pháp cho./someScript.sh & && echo 'ok' || echo 'ko'
Katie

4

Có một khái niệm "cắt ngắn".

Khi (expr1 && expr2)được đánh giá - expr2chỉ được đánh giá nếu exp1đánh giá là "đúng". Điều này là do cả hai expr1expr2phải đúng (expr1 && expr2)để trở thành đúng. Nếu expr1đánh giá thành "sai" expr2thì KHÔNG được đánh giá (cắt ngắn) vì (expr1 && expr2)đã "flase".

Hãy thử cách sau - giả sử tệp F1tồn tại & tệp F2không tồn tại:

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

Tương tự cho ||(hoặc) - nhưng cắt ngắn được đảo ngược.


5
Logic thường được gọi là "ngắn mạch". Tôi chưa bao giờ thấy cụm từ "cắt ngắn" được sử dụng. Tôi đề cập đến điều này để giúp tìm kiếm tài liệu tham khảo.
LS

-1

Các ví dụ trong câu trả lời của Shawn J. Goff là chính xác, nhưng lời giải thích là cách khác. Hãy kiểm tra:

Phía bên phải của && sẽ chỉ được đánh giá nếu trạng thái thoát của phía bên trái là NONZERO. | | là ngược lại: nó sẽ đánh giá phía bên phải chỉ khi trạng thái thoát bên trái là ZERO.


3
Bạn có biết rằng đối với shell, mã thoát không đánh giá là đúng và do đó mã thoát không khác ở phía bên trái của &&kết quả trong toàn bộ biểu thức để trả về false ?
phản ứng

1
Ai đó đã không chấp nhận các chỉnh sửa của bạn vì đó không phải là câu trả lời của bạn. Nếu bạn nghĩ rằng một số câu trả lời là không chính xác, bạn nên đánh giá thấp nó và có thể để lại nhận xét; nếu bạn nghĩ rằng nó cần một sự thay đổi, bạn nên để lại nhận xét. Chỉnh sửa là để sửa lỗi ngữ pháp, định dạng và lỗi chính tả không thay đổi ý nghĩa của câu trả lời.
techraf

1
@c gặpmode Tôi xin lỗi, bạn nói đúng, tôi nghĩ trong Linux zero = false và nonzero = true (như trong C và nhiều ngôn ngữ / môi trường / nền tảng khác). Tôi xin lỗi vì sự hiểu lầm.
Thử2Hỗ trợ
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.