Chính xác thì làm thế nào


50

Tôi luôn ngạc nhiên rằng trong thư mục /bincó một [chương trình.

Đây có phải là những gì được gọi khi chúng ta đang làm một cái gì đó như : if [ something ]?

Bằng cách gọi [chương trình một cách rõ ràng trong một vỏ, nó yêu cầu một tương ứng ], và khi tôi cung cấp dấu ngoặc đóng, nó dường như không làm gì cho dù tôi có chèn gì vào giữa các dấu ngoặc.

Không cần phải nói, cách thông thường để nhận trợ giúp về một chương trình không hoạt động, tức là man [cũng không [ --helphoạt động.


11
@IporSircer [đề cập đến testlệnh mặc dù, không expr, vì vậy nó phải làman test
Sergiy Kolodyazhnyy

8
man '['hoạt động tốt đối với tôi - hoặc bạn quên trích dẫn [hoặc bạn có một định nghĩa khác về "tác phẩm".
Toby Speight

3
Một vài cảnh báo: [đánh giá các đối số của nó, vì vậy bạn cần có khoảng trắng giữa tất cả chúng. [ a=b ]không phải là một so sánh: nó sẽ luôn luôn đúng (nó là một chuỗi đơn: "a = b", luôn được đánh giá là đúng ) Và bạn nên giới hạn số lượng đối số là 4 (mặc dù các triển khai gần đây sẽ cho phép nhiều hơn .. . giới hạn ở 4 làm cho nó dễ mang theo hơn. Ví dụ: [ "a" = "b" ]đã có 4 đối số: "a" "=" "b" và kết thúc không cần thiết của thử nghiệm arg: "]"). Nếu bạn cần thêm: kiểm tra chuỗi với ví dụ:if [ "$Var_a" = "foo" ] && [ "$Var_b" = "bar" ] ; then : do something ; fi
Olivier Dulac

1
@OlivierDulac a !của chính nó (không được giải thích và không được trích dẫn) sẽ không được thay thế, và thậm chí sẽ tốt hơn if ! [ .... Tất cả các bản mở rộng bash sử dụng !bao gồm ít nhất là trên nhân vật khác
muru

3
Bạn cũng nên lưu ý rằng cũng có một [-builtin trong bash(và có thể cả vỏ khác nữa), và điều này có thể được sử dụng thay vì /bin/[. Ngoài ra còn có test-command, trên nhiều hệ thống là một liên kết tượng trưng đến /bin/[(hoặc ngược lại) - nhưng trên các hệ thống khác là một lệnh riêng biệt.
Baard Kopperud

Câu trả lời:


63

Công [việc của lệnh là đánh giá các biểu thức kiểm tra. Nó trả về với trạng thái thoát 0 (có nghĩa là đúng ) khi biểu thức giải quyết thành đúng và một cái gì đó khác (có nghĩa là sai ) nếu không.

Không phải là nó không làm gì cả, chỉ là kết quả của nó được tìm thấy trong trạng thái thoát của nó. Trong một shell, bạn có thể tìm hiểu về trạng thái thoát của lệnh cuối cùng trong $?các shell giống như Bourne hoặc $statustrong hầu hết các shell khác (fish / rc / es / csh / tcsh ...).

$ [ a = a ]
$ echo "$?"
0
$ [ a = b ]
$ echo "$?"
1

Trong các ngôn ngữ khác như perl, trạng thái thoát được trả về ví dụ trong giá trị trả về của system():

$ perl -le 'print system("[", "a", "=", "a", "]")'
0

Lưu ý rằng tất cả các shell giống như Bourne hiện đại (và fish) đều có [lệnh tích hợp. Cái trong /binthường chỉ được thực thi khi bạn sử dụng shell khác hoặc khi bạn làm những việc như env [ foo = bar ]hoặc lệnh find . -exec [ -f {} ] \; -printđó perlở trên ...

Các [lệnh cũng được gọi bằng cái testtên. Khi được gọi là test, nó không yêu cầu một ]đối số kết thúc .

Mặc dù hệ thống của bạn có thể không có trang dành cho nam [, nhưng nó có thể có một trang dành cho test. Nhưng một lần nữa, lưu ý rằng nó sẽ ghi lại /bin/[hoặc /bin/testthực hiện. Để biết về [nội dung trong vỏ của bạn, bạn nên đọc tài liệu cho vỏ của bạn thay thế.

Để biết thêm thông tin về lịch sử của tiện ích đó và sự khác biệt với [[...]]biểu thức kiểm tra ksh, bạn có thể muốn xem qua câu hỏi và trả lời khác này tại đây .


Tốt, như thường lệ. Bạn có thể muốn thêm vào trong các bình luận tôi đã thêm bên dưới câu hỏi @Bregalad? hoặc có thể một số người thêm? Bằng cách đó, câu trả lời sẽ còn đầy đủ hơn về "cách thức hoạt động chính xác" (Tôi lưu ý rằng bạn đã cung cấp thông tin chính xác hơn về "]" so với tôi đã làm ^^)
Olivier Dulac

Tất cả các vỏ giống như Bourne (và cá) đều được tích hợp [lệnh 'Điều đó đúng trong thực tế trong thế kỷ 21, nhưng tôi khá chắc chắn rằng mình đã sử dụng vỏ mà không có [. Tôi không nhớ đó là biến thể Bourne hay tro phiên bản cổ.
Gilles 'SO- ngừng trở nên xấu xa'

@Gilles Shell Bourne đã triển khai cả hai [testnhư các nội trang với Unix System III. Trước đó, không có [testchỉ là một lệnh nhị phân bên ngoài.
jlliagre

@Gilles, tro ban đầu đã được xây dựng thử nghiệm (hợp nhất với expr), nhưng tùy chọn . Theo in-ulm.de/~mascheck/various/ash , BSD không có bản dựng thử nghiệm cho đến khoảng năm 2000. Tôi đã thêm "hiện đại".
Stéphane Chazelas

Tại sao trên thế giới bạn muốn làm gì find . -exec [ f {} ] \; -print? Lệnh find . -type f -printsẽ làm điều tương tự như vậy hiệu quả hơn nhiều ...
Đây không phải là tên thật của tôi

41

Tôi luôn ngạc nhiên rằng trong thư mục /bincó một [chương trình.

Bạn có quyền ngạc nhiên. Đó là một trong những lệnh POSIX hiếm, với tiện ích null ( :), không tôn trọng tệp lệnh cho phép quy ước ký tự (bộ ký tự tên tệp di động).

Là những gì được gọi khi chúng ta đang làm một cái gì đó như : if [ something ]?

Chính xác nhưng nó có thể được sử dụng mà không cần ifquá.

Bằng cách gọi [chương trình một cách rõ ràng trong một vỏ, nó yêu cầu một tương ứng ], và khi tôi cung cấp dấu ngoặc đóng, nó dường như không làm gì cho dù tôi có chèn gì vào giữa các dấu ngoặc.

Nó không có gì có thể nhìn thấy nhưng nó thực sự làm điều tương tự so với khi được sử dụng if, tức là nó đặt trạng thái thoát thành 0 (đúng) hoặc bất cứ điều gì khác (sai) tùy thuộc vào những gì bạn đặt trong dấu ngoặc. Đó là (vì một lý do) hành vi tương tự như testlệnh; sự khác biệt duy nhất là nó tìm kiếm kết thúc ]. Xem man testđể biết chi tiết.

Không cần phải nói, cách thông thường để nhận trợ giúp về một chương trình không hoạt động, tức là man [cũng không [ --helphoạt động.

Điều đó phụ thuộc vào hệ điều hành của bạn. man [chắc chắn hoạt động với tôi trên một vài bản phân phối Gnu / Linux chính thống nhưng nó không có trên Solaris.

[ --helpcó thể hoạt động hay không tùy thuộc vào việc triển khai vì dù sao nó cũng phá vỡ cú pháp, thiếu phần kết thúc ]. Hơn nữa, tiêu chuẩn POSIX cho lệnh test/[ quy định rõ ràng tất cả các tùy chọn, bao gồm cả --chấm dứt tùy chọn để cả hai [ --help ]test --helpcần phải trả lại truevà im lặng theo thiết kế. Lưu ý rằng những gì bạn đặt bên trong dấu ngoặc hoặc sau [và nhìn như tùy chọn (ví dụ -f file, -n stringvà những cầu thủ như) không phải là tùy chọn nhưng toán hạng .

Tất cả Bourne dịch viên kiểu vỏ hiện đại (như bash, ksh, dashzshđến tên một vài) thực hiện test/ [tiện ích nội bộ như một dựng sẵn vì vậy khi bạn sử dụng chúng, quyền trang hướng dẫn để chỉ có thể là một trong những vỏ, không phải là testmột.

Trước Unix System III (1981), shell Bourne không triển khai testtiện ích dưới dạng dựng sẵn nên chỉ thực hiện lệnh nhị phân bên ngoài. Không có [lệnh nào (nội bộ hoặc dựng sẵn) cho đến Unix System III, ví dụ như trong Phiên bản Unix 7, bạn phải gõ:

if test something ; then

thay vì:

if [ something ] ; then

"Người đàn ông [chắc chắn làm việc cho tôi trên dòng chính các bản phân phối GNU / Linux" Hmm .. Centos (phải thừa nhận là 6.8 vẫn) rõ ràng là không chính đủ :) man testtác phẩm nhưng không phải man [ Mặt khác môi trường Cygwin của tôi không biết về man [!
Adam

1
@Adam Vâng, bạn nói đúng, gần đây hơn tôi nghĩ mặc dù tôi đã không viết tất cả các bản phân phối Linux chính thống, chỉ là nó hoạt động với tôi (tức là trên những bản tôi đã thử nghiệm). Đó là bản sao OL 7.2 (RHEL 7.2) và Mint 17.1 (Ubuntu 14.04).
jlliagre

man [dường như không hoạt động trên Manjaro (dựa trên Arch Linux). Hướng dẫn cho testcác danh sách [ --helpnhư một lời mời hợp lệ sẽ hiển thị trợ giúp, nhưng thú vị là nó không, và thay vào đó phàn nàn về việc mất tích ], giống như với --version. Thêm ]không làm gì cả, vì vậy dường như không thể nhận được sự giúp đỡ nào khác ngoài man test.
Darkhogg

@Darkhogg Bạn có thể thử /usr/bin/[ --helphoặc /bin/[ --help.
jlliagre

1
@jlliagre Bạn hoàn toàn đúng, tôi đã sử dụng các nội trang. env [ --helpcũng như /usr/bin/[ --helplàm việc hoàn toàn tốt (mặc dù tôi cần trích dẫn /usr/bin/[hoặc zsh phàn nàn).
Darkhogg

10

[thực sự thường được gọi là testlệnh. Việc sử dụng điển hình của lệnh này chỉ đơn giản là để đánh giá các biểu thức và trả về điều kiện của chúng - đúng hoặc sai. Nó thường được sử dụng trong các if-then-else-ficâu lệnh, mặc dù nó có thể được sử dụng bên ngoài các ifcâu lệnh để chạy một cách có điều kiện các lệnh khác thông qua shell &&hoặc ||toán tử, như vậy.

$ [ -e /etc/passwd  ] && echo "File exists"
File exists

$ test -e /etc/passwd && echo "File exists"
File exists

Cụ thể hơn, đánh giá được truyền đến các lệnh khác thông qua trạng thái thoát. Một số chương trình có thể chọn xuất trạng thái thoát để biểu thị các loại sự kiện khác nhau - chương trình hoàn tất thành công, lỗi thuộc loại cụ thể xảy ra trong khi thực hiện hoặc lỗi cú pháp. Trong trường hợp của testlệnh, có 0nghĩa là đúng và 1có nghĩa là sai. Như Stephan đã chỉ ra, lỗi cú pháp tạo ra trạng thái thoát của 2.

Vị trí của nó phụ thuộc vào hệ thống của bạn và nó cũng giải thích lý do tại sao bạn không thấy trang man khi bạn làm như vậy man [. Ví dụ, trên FreeBSD, nó nằm dưới /bin. Trên Linux (hoặc trong trường hợp cụ thể của tôi, Ubuntu 16.04), nó nằm trong /usr/bin/. Nếu bạn làm man [hoặc man testtrên một hệ thống Linux, bạn sẽ thấy tài liệu tương tự mở. Cũng cần lưu ý rằng vỏ của bạn có thể có cách thực hiện riêng test.

Cũng cần lưu ý rằng lệnh này có vấn đề , mà việc triển khai của Korn shell (thường được gọi là tham chiếu "biểu thức điều kiện" với dấu ngoặc vuông, [[ "$USER" = "root" ]]) tìm cách giải quyết. Tính năng này cũng được sử dụng bởi các shell khác như bashzsh.


/usr/bin/cho Amazon Linux là tốt.
franklinsijo

@ StéphaneChazelas Cảm ơn bạn. Trả lời chỉnh sửa cho phù hợp
Sergiy Kolodyazhnyy

3

Không man [phải cũng không [ --helphoạt động

Trên một số distro (ví dụ Ubuntu), man [theo một liên kết tượng trưng đến test(1). Trên những người khác (ví dụ Arch), đây không phải là trường hợp. (Nhưng testtrang man cũng sử dụng tài liệu [)


type -a [ cho bạn thấy rằng có cả shell dựng sẵn và thực thi.

$ type -a [
[ is a shell builtin
[ is /usr/bin/[

bash-dựng sẵn [ --helpchỉ in một thông báo lỗi. (Nhưng vì nó là một nội dung, bạn có thể sử dụng help [hoặc xem trang bash man / docs).

/usr/bin/[ --help in toàn bộ đầu ra trợ giúp (đối với phiên bản GNU Coreutils), bắt đầu bằng:

$ /usr/bin/[ --help
Usage: test EXPRESSION
  or:  test
  or:  [ EXPRESSION ]
  or:  [ ]
  or:  [ OPTION
Exit with the status determined by EXPRESSION.

      --help     display this help and exit
      --version  output version information and exit

và sau đó mô tả cú pháp được phép cho EXPRESSION.

Đây là một cách khác mà bạn có thể đã tìm ra [testtương đương.


BTW, nếu bạn đang lập trình cho bash (hoặc viết một lớp tương tác), tôi khuyên bạn nên [[thay thế [. Nó tốt hơn theo nhiều cách, xem các liên kết trong câu trả lời của Serg.


2

[lệnh trả về trạng thái thoát zero nếu biểu thức, được chứa trong các đối số của nó, được coi là đúng và trạng thái thoát không bằng 0 nếu biểu thức, chứa trong các đối số của nó, được coi là sai. Nó cũng thất bại với thông báo lỗi nếu đối số cuối cùng của nó không ](điều này được thực hiện hoàn toàn vì lý do thẩm mỹ).

Ví dụ:

[ hello ]
echo "Exit-status of [ hello ] is:" $?
[ abc = abc ]
echo "Exit-status of [ abc = abc ] is:" $?
[ ]
echo "Exit-status of [ ] is:" $?
[ abc = def ]
echo "Exit-status of [ abc = def ] is:" $?

Đầu ra sẽ xuất hiện:

Trạng thái thoát của [hello] là: 0       - vì chuỗi không trống được coi là đúng 
Trạng thái thoát của [abc = abc] là: 0   - vì 'abc' thực sự giống với 'abc' 
Trạng thái thoát của [] là : 1             - vì chuỗi rỗng được coi là sai 
Trạng thái thoát của [abc = def] là: 1   - vì 'abc' thực sự khác với 'def'

Tuy nhiên, bash và nhiều shell khác thực sự thường không gọi /bin/[(hoặc /usr/bin/[) trong các trường hợp này, mà gọi lệnh tích hợp với chính xác cùng một hành vi thay vào đó (hoàn toàn vì lý do hiệu suất). Để gọi /bin/[(không phải thay thế được tích hợp sẵn), bạn cần chỉ định rõ ràng đường dẫn của nó (ví dụ: /bin/[ hello ]bạn không cần phải thêm tiền tố ]với dirname mặc dù ) hoặc để cấu hình shell không sử dụng thay thế tích hợp (ví dụ: enable -n [trong bash).

PS: Như đã nói trong các câu trả lời khác, [có liên quan đến test. Nhưng test, không giống như [, không đòi hỏi ]như là đối số cuối cùng của nó (và không mong đợi nó ở tất cả; bổ sung thêm ]cho testlập luận có thể gây ra nó để thất bại với thông báo lỗi hoặc để trả về kết quả sai) . Các /bin/test/bin/[có thể giải quyết đến cùng một tập tin (ví dụ như ai symlinked ; trong trường hợp này dòng hành vi có lẽ được thực hiện bởi việc phân tích các hiện gọi là lệnh trong test/ [mã riêng của mình) hoặc các tập tin khác nhau. Đối với test, shell cũng thường gọi thay thế tích hợp, trừ khi đường dẫn được chỉ định rõ ràng ( /bin/test) hoặc nó được cấu hình không làm như vậy (enable -n test).

PPS: Không giống như test[, hiện đại ifkhông bao giờ là một tập tin thực sự. Đó là một phần của cú pháp shell (ví dụ bash): if commandA; then commandB; fi(dòng mới có thể được sử dụng thay cho dấu chấm phẩy) gây ra commandBđược thực thi if-and-only-if commandAvới trạng thái zero. Điều này hoàn toàn phù hợp với hành vi của testhoặc [, cho phép kết hợp chúng như if [ "$a" = foo ]; then …; fi (hoặc if test "$a" = foo; then …; fi- chỉ ít đọc hơn) . Tuy nhiên, các tập lệnh hiện đại thường sử dụng [[thay vì testhoặc [, mà (như if) không bao giờ là một tập tin thực sự, mà luôn là một phần của cú pháp shell.

PPPS: Như đối với man- không bao giờ mong đợi mancó một bài viết về mọi lệnh trong hệ thống tệp của bạn. Thông tin về một số thông tin (thậm chí là "thực", file-based) lệnh có thể bị thiếu, trên một số vỏ built-in có thể hiện không chỉ trong phạm vi một bài báo dành riêng cho vỏ cụ thể (đó là nơi mà bạn chắc chắn sẽ tìm thấy thông tin về test, [, if, [[) Tuy nhiên, nhiều bản phân phối có man-articles rõ ràng cho test[. (Về --help, nó không được công nhận với testlý do rõ ràng: nó cần xử lý các trường hợp lặng lẽ như a=--help; test "$a"; trên một số bản phân phối [ --help(không đóng ]) vẫn hiển thị trợ giúp, đối với một số thì không.)


3
Lưu ý rằng đó iflà một lệnh lên tới Unix V6. Unix V7 (1979) đi kèm với vỏ Bourne (với if-then-else-ficấu trúc của nó ) và testlệnh mới .
Stéphane Chazelas
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.