Tôi đang đọc các ví dụ bash về if
nhưng một số ví dụ được viết với dấu ngoặc đơn:
if [ -f $param ]
then
#...
fi
những người khác với dấu ngoặc vuông:
if [[ $? -ne 0 ]]
then
start looking for errors in yourlog
fi
Sự khác biệt là gì?
Tôi đang đọc các ví dụ bash về if
nhưng một số ví dụ được viết với dấu ngoặc đơn:
if [ -f $param ]
then
#...
fi
những người khác với dấu ngoặc vuông:
if [[ $? -ne 0 ]]
then
start looking for errors in yourlog
fi
Sự khác biệt là gì?
Câu trả lời:
Đơn []
là các thử nghiệm điều kiện tuân thủ vỏ posix.
Double [[]]
là một phần mở rộng cho tiêu chuẩn []
và được hỗ trợ bởi bash và các shell khác (ví dụ zsh, ksh). Họ hỗ trợ các hoạt động bổ sung (cũng như các hoạt động posix tiêu chuẩn). Ví dụ: ||
thay vì -o
và regex khớp với =~
. Một danh sách đầy đủ hơn về sự khác biệt có thể được tìm thấy trong phần hướng dẫn sử dụng bash trên các cấu trúc có điều kiện .
Sử dụng []
bất cứ khi nào bạn muốn tập lệnh của bạn có thể di động trên các shell. Sử dụng [[]]
nếu bạn muốn các biểu thức điều kiện không được hỗ trợ bởi []
và không cần phải di động.
[[ ]]
(ví dụ: bash với #!/bin/bash
hoặc #!/usr/bin/env bash
), bạn nên sử dụng tùy chọn di động. Các tập lệnh giả định / bin / sh hỗ trợ các tiện ích mở rộng như thế này sẽ phá vỡ các hệ điều hành như các bản phát hành Debian và Ubuntu gần đây trong trường hợp không phải vậy.
Khác biệt về hành vi
Đã thử nghiệm trong Bash 4.3.11:
Gia hạn POSIX vs Bash:
[
là POSIX[[
là một tiện ích mở rộng Bash¹ được ghi lại tại: https://www.gnu.org/software/bash/manual/bash.html#Conditable-Constructslệnh thường xuyên vs ma thuật
[
chỉ là một lệnh thông thường với một cái tên kỳ lạ.
]
chỉ là một đối số [
ngăn chặn các đối số tiếp theo được sử dụng.
Ubuntu 16.04 thực sự có một tệp thực thi cho nó /usr/bin/[
được cung cấp bởi coreutils, nhưng phiên bản tích hợp bash được ưu tiên.
Không có gì được thay đổi theo cách Bash phân tích lệnh.
Cụ thể, <
là chuyển hướng &&
và ||
ghép nhiều lệnh, ( )
tạo các lớp con trừ khi thoát ra \
và mở rộng từ diễn ra như bình thường.
[[ X ]]
là một cấu trúc duy nhất X
được phân tích cú pháp một cách kỳ diệu. <
, &&
, ||
Và ()
được đối xử đặc biệt, và các quy tắc từ tách khác nhau.
Ngoài ra còn có sự khác biệt như =
và =~
.
Trong Bashese: [
là một lệnh tích hợp và [[
là một từ khóa: https://askubfox.com/questions/445749/whats-the-difference-b between-shell-buildin-and-shell - keyword
<
[[ a < b ]]
: so sánh từ điển[ a \< b ]
: Giống như trên. \
bắt buộc hoặc cách khác không chuyển hướng như đối với bất kỳ lệnh nào khác. Bash mở rộng.expr a \< b > /dev/null
: POSIX tương đương², xem: Làm thế nào để kiểm tra các chuỗi cho từ vựng nhỏ hơn hoặc bằng trong Bash?&&
và ||
[[ a = a && b = b ]]
: đúng, hợp lý và[ a = a && b = b ]
: lỗi cú pháp, được &&
phân tích cú pháp như một dấu tách lệnh ANDcmd1 && cmd2
[ a = a -a b = b ]
: tương đương, nhưng không được chấp nhận bởi POSIX³[ a = a ] && [ b = b ]
: POSIX và tương đương đáng tin cậy(
[[ (a = a || a = b) && a = b ]]
: sai[ ( a = a ) ]
: lỗi cú pháp, ()
được hiểu là một nhánh con[ \( a = a -o a = b \) -a a = b ]
: tương đương, nhưng ()
không được chấp nhận bởi POSIX{ [ a = a ] || [ a = b ]; } && [ a = b ]
POSIX tương đương 5tách từ và tạo tên tệp khi mở rộng (split + global)
x='a b'; [[ $x = 'a b' ]]
: đúng, trích dẫn không cần thiếtx='a b'; [ $x = 'a b' ]
: lỗi cú pháp, mở rộng thành [ a b = 'a b' ]
x='*'; [ $x = 'a b' ]
: lỗi cú pháp nếu có nhiều hơn một tệp trong thư mục hiện tại.x='a b'; [ "$x" = 'a b' ]
: Tương đương POSIX=
[[ ab = a? ]]
: đúng, vì nó không khớp mẫu ( * ? [
là ma thuật). Không toàn cầu mở rộng để tập tin trong thư mục hiện tại.[ ab = a? ]
: toàn a?
cầu mở rộng. Vì vậy, có thể đúng hoặc sai tùy thuộc vào các tệp trong thư mục hiện tại.[ ab = a\? ]
: sai, không mở rộng toàn cầu=
và ==
giống nhau ở cả hai [
và [[
, nhưng ==
là một phần mở rộng Bash.case ab in (a?) echo match; esac
: Tương đương POSIX[[ ab =~ 'ab?' ]]
: sai 4 , mất phép thuật với''
[[ ab? =~ 'ab?' ]]
: thật=~
[[ ab =~ ab? ]]
: đúng, POSIX kết hợp biểu thức chính quy mở rộng , ?
không mở rộng toàn cầu[ a =~ a ]
: lỗi cú pháp. Không có bash tương đương.printf 'ab\n' | grep -Eq 'ab?'
: Tương đương POSIX (chỉ dữ liệu một dòng)awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?'
: Tương đương POSIX.Khuyến cáo : luôn luôn sử dụng []
.
Có tương đương POSIX cho mọi [[ ]]
cấu trúc tôi đã thấy.
Nếu bạn sử dụng [[ ]]
bạn:
[
chỉ là một lệnh thông thường với một cái tên kỳ lạ, không có ngữ nghĩa đặc biệt nào được tham gia.Lấy cảm hứng từ [[...]]
cấu trúc tương đương trong vỏ Korn
² nhưng không thành công đối với một số giá trị a
hoặc b
(như +
hoặc index
) và không so sánh số nếu a
và b
trông giống như số nguyên thập phân. expr "x$a" '<' "x$b"
làm việc xung quanh cả hai.
Và cũng thất bại đối với một số giá trị a
hoặc b
thích !
hoặc (
.
4 trong bash 3.2 trở lên và cung cấp khả năng tương thích với bash 3.1 không được bật (như với BASH_COMPAT=3.1
)
5 mặc dù việc nhóm (ở đây với {...;}
nhóm lệnh thay vì (...)
chạy một lớp con không cần thiết) là không cần thiết vì các toán tử shell ||
và &&
(trái ngược với các toán tử ||
và &&
[[...]]
toán tử -o
/ -a
[
toán tử) có quyền ưu tiên như nhau. Như vậy [ a = a ] || [ a = b ] && [ a = b ]
sẽ tương đương.
[]
nên đọc là Sở thích của tôi : sử dụng []
nếu bạn không muốn mất tính di động . Như đã nêu ở đây : Nếu tính di động / tuân thủ POSIX hoặc BourneShell là một mối quan tâm, nên sử dụng cú pháp cũ. Mặt khác, tập lệnh yêu cầu BASH, Zsh hoặc KornShell, cú pháp mới thường linh hoạt hơn, nhưng không nhất thiết phải tương thích ngược. Tôi thà đi cùng [[ ab =~ ab? ]]
nếu tôi có thể và không phải lo lắng về khả năng tương thích ngược hơnprintf 'ab' | grep -Eq 'ab?'
Bên trong dấu ngoặc đơn để kiểm tra điều kiện (ví dụ [...]), một số toán tử như đơn =
được hỗ trợ bởi tất cả các shell, trong khi việc sử dụng toán tử ==
không được hỗ trợ bởi một số shell cũ.
Bên trong dấu ngoặc kép để kiểm tra điều kiện (tức là [[...]]), không có sự khác biệt giữa việc sử dụng =
hoặc ==
trong vỏ cũ hoặc mới.
Chỉnh sửa: Tôi cũng cần lưu ý rằng: Trong bash, luôn luôn sử dụng dấu ngoặc kép [[...]] nếu có thể, vì nó an toàn hơn dấu ngoặc đơn. Tôi sẽ minh họa tại sao với ví dụ sau:
if [ $var == "hello" ]; then
nếu $ var xảy ra là null / trống, thì đây là những gì tập lệnh nhìn thấy:
if [ == "hello" ]; then
Điều này sẽ phá vỡ kịch bản của bạn. Giải pháp là sử dụng dấu ngoặc kép hoặc luôn nhớ đặt dấu ngoặc kép quanh các biến của bạn ( "$var"
). Dấu ngoặc kép là thực hành mã hóa phòng thủ tốt hơn.
[[
là một từ khóa bash tương tự (nhưng mạnh hơn) [
lệnh.
Xem
http://mywiki.wooledge.org/BashFAQ/031 và http://mywiki.wooledge.org/BashGuide/TestsAndCond điều kiện
Trừ khi bạn viết cho POSIX sh, chúng tôi khuyên bạn nên [[
.
bạn có thể sử dụng dấu ngoặc vuông đôi để khớp regex ánh sáng, ví dụ:
if [[ $1 =~ "foo.*bar" ]] ; then
(miễn là phiên bản bash bạn đang sử dụng hỗ trợ cú pháp này)
Hướng dẫn Bash nói:
Khi được sử dụng với [[, các toán tử '<' và '>' sắp xếp từ vựng theo ngôn ngữ hiện tại. Lệnh kiểm tra sử dụng thứ tự ASCII.
(Lệnh kiểm tra giống hệt với [])