Toán tử logic đơn giản trong Bash


256

Tôi có một vài biến và tôi muốn kiểm tra điều kiện sau (viết bằng chữ, sau đó tôi đã thất bại trong kịch bản bash):

if varA EQUALS 1 AND ( varB EQUALS "t1" OR varB EQUALS "t2" ) then 

do something

done.

Và trong nỗ lực thất bại của mình, tôi đã nghĩ ra:

if (($varA == 1)) && ( (($varB == "t1")) || (($varC == "t2")) ); 
  then
    scale=0.05
  fi

Câu trả lời:


682

Những gì bạn đã viết thực sự gần như hoạt động (nó sẽ hoạt động nếu tất cả các biến là số), nhưng đó không phải là một cách thành ngữ.

  • (…)dấu ngoặc chỉ ra một subshell . Những gì bên trong chúng không phải là một biểu thức như trong nhiều ngôn ngữ khác. Đây là danh sách các lệnh (giống như dấu ngoặc đơn bên ngoài). Các lệnh này được thực thi trong một quy trình con riêng biệt, do đó, bất kỳ chuyển hướng, gán, v.v. được thực hiện bên trong dấu ngoặc đơn đều không có tác dụng bên ngoài dấu ngoặc đơn.
    • Với ký hiệu đô la hàng đầu, $(…)là sự thay thế lệnh : có một lệnh bên trong dấu ngoặc đơn và đầu ra từ lệnh được sử dụng như một phần của dòng lệnh (sau khi mở rộng thêm trừ khi thay thế nằm giữa dấu ngoặc kép, nhưng đó là một câu chuyện khác ) .
  • { … }dấu ngoặc nhọn giống như dấu ngoặc đơn ở chỗ chúng nhóm các lệnh, nhưng chúng chỉ ảnh hưởng đến phân tích cú pháp, không nhóm. Chương trình x=2; { x=4; }; echo $xin 4, trong khi x=2; (x=4); echo $xin 2. (Ngoài ra, dấu ngoặc nhọn yêu cầu khoảng trắng xung quanh chúng và dấu chấm phẩy trước khi đóng, trong khi dấu ngoặc đơn thì không. Đó chỉ là một cú pháp.
    • Với một ký hiệu đô la hàng đầu, ${VAR}là một mở rộng tham số , mở rộng đến giá trị của một biến, với các biến đổi bổ sung có thể.
  • ((…))dấu ngoặc kép bao quanh một lệnh số học , nghĩa là tính toán trên các số nguyên, với một cú pháp giống với các ngôn ngữ lập trình khác. Cú pháp này chủ yếu được sử dụng cho các bài tập và trong các điều kiện.
    • Cú pháp tương tự được sử dụng trong các biểu thức số học $((…)), mở rộng thành giá trị nguyên của biểu thức.
  • [[ … ]]dấu ngoặc kép bao quanh biểu thức điều kiện . Các biểu thức điều kiện hầu hết được xây dựng trên các toán tử như -n $variableđể kiểm tra xem một biến có trống không và -e $fileđể kiểm tra nếu một tệp tồn tại. Ngoài ra còn có các toán tử đẳng thức chuỗi: "$string1" == "$string2"(hãy cẩn thận rằng phía bên tay phải là một mẫu, ví dụ: [[ $foo == a* ]]kiểm tra nếu $foobắt đầu atrong khi [[ $foo == "a*" ]]kiểm tra nếu $foochính xác a*), và các toán tử quen thuộc !, &&||phủ định cũng như dấu ngoặc đơn để phân nhóm. Lưu ý rằng bạn cần một khoảng trắng xung quanh mỗi toán tử (ví dụ: [[ "$x" == "$y" ]]không [[ "$x"=="$y" ]]) và khoảng trắng hoặc ký tự như ;cả bên trong và bên ngoài dấu ngoặc (ví dụ: [[ -n $foo ]]không[[-n $foo]]).
  • [ … ]dấu ngoặc đơn là một dạng thay thế của các biểu thức điều kiện có nhiều quirks hơn (nhưng cũ hơn và dễ mang theo hơn). Đừng viết bất cứ điều gì cho bây giờ; bắt đầu lo lắng về chúng khi bạn tìm thấy các tập lệnh có chứa chúng.

Đây là cách thành ngữ để viết bài kiểm tra của bạn trong bash:

if [[ $varA == 1 && ($varB == "t1" || $varC == "t2") ]]; then

Nếu bạn cần tính di động đối với các shell khác, đây sẽ là cách (lưu ý trích dẫn bổ sung và các bộ dấu ngoặc riêng biệt xung quanh từng thử nghiệm riêng lẻ và sử dụng =toán tử truyền thống thay vì ==biến thể ksh / bash / zsh ):

if [ "$varA" = 1 ] && { [ "$varB" = "t1" ] || [ "$varC" = "t2" ]; }; then

31
Bài đăng tuyệt vời, tóm tắt ngoặc chỉ là lý tưởng.
KomodoDave

10
Tốt hơn là sử dụng ==để phân biệt so sánh với việc gán một biến (cũng là vậy =)
Will Sheppard

1
Oh, tôi có nghĩa là dấu ngoặc đơn (tròn), xin lỗi vì sự nhầm lẫn. Những người trong [[ $varA = 1 && ($varB = "t1" || $varC = "t2") ]]không bắt đầu một quy trình phụ mặc dù dấu đầu dòng đầu tiên nói rõ ràng: "Cái gì bên trong [dấu ngoặc đơn] không phải là một biểu thức như trong nhiều ngôn ngữ khác" - nhưng chắc chắn là ở đây! Điều đó có lẽ là hiển nhiên đối với các wash bash có kinh nghiệm, nhưng ngay cả với tôi, ngay lập tức. Sự nhầm lẫn có thể phát sinh vì các dấu ngoặc đơn có thể được sử dụng trong một ifcâu lệnh, chỉ không trong các biểu thức bên trong dấu ngoặc kép.
Peter - Tái lập Monica

2
@protagonist ==không thực sự là nhiều người thành ngữ hơn =. Chúng có cùng ý nghĩa, nhưng ==là một biến thể ksh cũng có sẵn trong bash và zsh, trong khi đó =là di động. Thực sự không có bất kỳ lợi thế nào khi sử dụng ==và nó không hoạt động trong sh.
Gilles 'SO- ngừng trở nên xấu xa'

2
@WillSheppard Đã có nhiều khác biệt khác giữa so sánh và gán: so sánh nằm trong dấu ngoặc, gán không; so sánh có không gian xung quanh toán tử, gán không; gán có một tên biến ở bên trái, chỉ so sánh hiếm khi có một cái gì đó trông giống như một tên biến ở bên trái và bạn có thể và nên đặt dấu ngoặc kép. Bạn có thể viết ==bên trong [[ … ]], nếu bạn muốn nhưng =có lợi thế là cũng làm việc [ … ], vì vậy tôi khuyên bạn không nên tập thói quen sử dụng ==.
Gilles 'SO- ngừng trở nên xấu xa'

34

rất gần

if [[ $varA -eq 1 ]] && [[ $varB == 't1' || $varC == 't2' ]]; 
  then 
    scale=0.05
  fi

nên làm việc.

phá vỡ nó

[[ $varA -eq 1 ]] 

là một so sánh số nguyên trong đó như

$varB == 't1'

là một chuỗi so sánh. mặt khác, tôi chỉ nhóm các so sánh một cách chính xác.

Dấu ngoặc vuông phân định biểu thức có điều kiện. Và, tôi thấy những điều sau đây là một bài đọc tốt về chủ đề này: "(IBM) Làm sáng tỏ bài kiểm tra, [, [[, ((và, nếu-thì-khác"


Chỉ cần chắc chắn: Việc trích dẫn trong 't1'là không cần thiết, phải không? Bởi vì trái ngược với các hướng dẫn số học trong ngoặc đơn, trong đó t1sẽ là một biến, t1trong một biểu thức điều kiện trong ngoặc kép chỉ là một chuỗi ký tự. Tức [[ $varB == 't1' ]]là , giống hệt như [[ $varB == t1 ]], phải không?
Peter - Phục hồi Monica

6

Một phiên bản rất di động (thậm chí đến vỏ bourne cũ):

if [ "$varA" = 1 -a \( "$varB" = "t1" -o "$varB" = "t2" \) ]
then    do-something
fi

Điều này có chất lượng bổ sung khi chỉ chạy tối đa một quy trình con (đó là quy trình [), bất kể hương vị vỏ.

Thay thế =bằng -eqnếu biến chứa giá trị số, vd

  • 3 -eq 03 là đúng, nhưng
  • 3 = 03là sai. (so sánh chuỗi)

3

Đây là mã cho phiên bản ngắn của câu lệnh if-then-other:

( [ $a -eq 1 ] || [ $b -eq 2 ] ) && echo "ok" || echo "nok"

Hãy chú ý những điều sau:

  1. ||&&các toán hạng bên trong nếu điều kiện (tức là giữa các dấu ngoặc tròn) là các toán hạng logic (hoặc / và)

  2. ||&&toán hạng bên ngoài nếu điều kiện có nghĩa là / khác

Thực tế tuyên bố nói:

if (a = 1 hoặc b = 2) thì "ok" khác "nok"


Dấu ngoặc đơn ( ... )tạo ra một subshell. Có thể muốn sử dụng niềng răng { ... }thay thế. Bất kỳ trạng thái nào được tạo trong một mạng con sẽ không hiển thị trong trình gọi.
Clint Pachl

0
if ([ $NUM1 == 1 ] || [ $NUM2 == 1 ]) && [ -z "$STR" ]
then
    echo STR is empty but should have a value.
fi
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.