Chẳng hạn, lệnh sau không hoạt động:
if [[-e xyz]]; then echo File exists;fi
ksh đưa ra lỗi sau
[[-e: command not found
Có phải vì "[[-" không rõ ràng?
Chẳng hạn, lệnh sau không hoạt động:
if [[-e xyz]]; then echo File exists;fi
ksh đưa ra lỗi sau
[[-e: command not found
Có phải vì "[[-" không rõ ràng?
Câu trả lời:
Lời giải thích đơn giản nhất sẽ là, bởi vì trong cuốn hướng dẫn nó xuất hiện như [[ expression ]]
vậy phải có khoảng trống giữa [[
và expression
và bế mạc ]]
. Nhưng tất nhiên chúng ta có thể cố gắng nhìn vào nó sâu hơn. Shell có ngữ pháp hơi phức tạp và phụ thuộc rất nhiều vào khái niệm "tách từ". Cụ thể, ksh (1) trạng thái thủ công:
Shell bắt đầu phân tích cú pháp đầu vào của nó bằng cách chia nó thành các từ. Các từ, là chuỗi các ký tự, được phân cách bằng các ký tự khoảng trắng không được trích dẫn (dấu cách, tab và dòng mới) hoặc ký tự meta (<,>, |,;, &, (và)). Ngoài việc phân định các từ, khoảng trắng và tab bị bỏ qua, trong khi các dòng mới thường phân định các lệnh.
Vì vậy, như đã nêu trong hướng dẫn, chuỗi ký tự [[-e
được coi là một từ vỏ. ksh
sẽ tìm kiếm lệnh đó trong danh sách các toán tử tích hợp và toán tử đặc biệt (như for
hoặc while
), sau đó tìm lệnh bên ngoài - và voilà - không tìm thấy, do đó không tìm thấy thông báo lỗi về lệnh.
Trong trường hợp này [[
cũng không phải là siêu ký tự đặc biệt. Nếu có, -e
phần trong [[-e
đó sẽ được coi là một từ vỏ, không phải là một đối số với [[
chính nó. Tuy nhiên, [[
được mô tả là lệnh ghép và hướng dẫn sử dụng cho biết như sau:
Các lệnh ghép được tạo bằng các từ dành riêng sau - những từ này chỉ được nhận ra nếu chúng không được trích dẫn và nếu chúng được sử dụng làm từ đầu tiên của lệnh (nghĩa là chúng không thể được đặt trước bởi các phép gán tham số hoặc chuyển hướng):
Vì vậy, [[
để được công nhận là lệnh ghép, nó phải là từ đầu tiên của danh sách lệnh hoặc danh sách lệnh, theo định nghĩa trước đó của "từ" ngụ ý nó phải được phân tách bằng khoảng trắng, tab hoặc dòng mới từ khác từ / lập luận.
Bạn đã hỏi trong các nhận xét : "Tại sao trình phân tích cú pháp không thể dừng ngay khi tìm thấy mẫu" [["và coi đó là khởi đầu của một lệnh có điều kiện?" Câu trả lời ngắn có lẽ là do 1) ảnh hưởng của [
cú pháp vì ban đầu nó là một lệnh bên ngoài và để tuân thủ tiêu chuẩn POSIX tồn tại dưới dạng lệnh bên ngoài ngay cả ngày nay và 2) vì trình phân tích cú pháp shell được xây dựng như vậy. Trình phân tích cú pháp Shell có thể nhận ra các ký tự đặc biệt được phân tách không phải dấu cách khác: echo $((2+2))
và (echo foobar)
hoạt động hoàn toàn tốt. Có thể trong tương lai khi ksh
sự phát triển tiếp tục hoặc dường như có một ngã ba hoặc nhân bản (như mksh
hoặc pdksh
) ai đó sẽ thực hiện cú pháp không gian trống trong [[-e
.
[[
được gọi là "từ dành riêng" (xem phần 2.9 của Ngôn ngữ lệnh Shell ). Theo định nghĩa POSIX, từ dành riêng phải được phân cách bằng dấu cách. Ngược lại (
là một toán tử và các trạng thái tiêu chuẩn trong phần 2.9 "các biểu diễn bao gồm khoảng cách giữa các mã thông báo ở một số nơi <blank>
không cần thiết (khi một trong số các mã thông báo là toán tử)". Xem thảo luận liên quan: Ngữ pháp POSIX Shell: Tại sao nhóm Brace cần không gian đầu tiên nhưng Subshell không?char
là một từ khóa nhưng bạn vẫn không thể viết charsomeletter = 'A';
và mong đợi trình phân tích cú pháp dừng lại sau khi nhìn thấy char
.
i--<=++j
, và trình biên dịch không có vấn đề phân tích cú pháp như i -- <= ++ j
.
_
). Ksh có (
một toán tử và (echo hello)
phân tích cú pháp như ( echo hello )
. Nó đã if
, {
, [[
, và các từ khóa , và ifx
, {x
và [[x
là mỗi một chiếc thẻ - như thế nào charsomeletter
là một C token. Ngược lại, một (x
mã thông báo trong ksh là hai mã thông báo - giống như i--
hai mã thông báo trong C. Điều gì về mặt khái niệm thậm chí có nghĩa là một toán tử khác nhau giữa các vỏ kiểu Bourne (như ksh) và C. Nhưng Peter A. Schneider đã chỉ ra một tương tự từ vựng thực sự.
Điều quan trọng cần lưu ý là đó [
là một lệnh và từ khóa shell [[
trong bash và ksh được dựa trên [
.
[[
được sử dụng theo cách tương tự [
. Đôi khi bạn thậm chí có thể thay thế [
]
với [[
]]
không có thay đổi trong hành vi. Với [
, giống như bất kỳ lệnh nào, một khoảng trắng là bắt buộc giữa lệnh và đối số của nó. Áp dụng tương tự cho [[
.
Chúng tôi đã từng có /usr/bin/[
. Bây giờ hầu hết các shell đã tích [
hợp sẵn để đạt hiệu quả, nhưng cú pháp là như nhau. Trong shell cung cấp [[
, nó hoạt động như một sự thay thế linh hoạt hơn[
.
Dưới đây là mô tả cho [
trong bash:
$ help [
[: [ arg... ]
Evaluate conditional expression.
This is a synonym for the "test" builtin, but the last argument must
be a literal `]', to match the opening `['.
Vì vậy, [
tương đương với test
(ngoài việc mong đợi một ]
cuộc tranh luận ở cuối). help test
sẽ cung cấp thêm chi tiết về nó. Bạn có thể so sánh điều này với help [[
.
Ngoài ra còn có một trang man cho lệnh bên ngoài [
( man \[
).
Trong trường hợp
if [[-e
[
phải [[
là một lệnh, ở đó. Từ đầy đủ [[-e
là.if [[-e
cho nó một thử nghiệm cho đúng / sai. Vì vậy, một lệnh [[-e
tồn tại? Có phải vì "[[-" không rõ ràng?
Đúng. Hay không. [[-e
là những gì nó là: không có gì mà shell hiểu vì vậy nó giả sử nó là lệnh riêng của nó. ;-)
[[-e
là một tên lệnh có khả năng hợp lệ (nếu trông lạ).
Không gian là một dấu phân cách và được yêu cầu. Như bạn có thể thấy từ shellcheck
:
$ shellcheck gmail-browse-msgs-algorithm.sh
In gmail-browse-msgs-algorithm.sh line 847:
[[$Today != "${DaysArr[ i + DAY_DELETED_ON_NDX ]}" ]] && continue
^-- SC1035: You need a space after the [[ and before the ]].
(Cả hỗ trợ ksh và bash [[
và không hoạt động mà không có khoảng trống. Shellcheck cung cấp chính xác đầu ra đó với các tập lệnh ksh và bash tương tự có chứa dòng lỗi đó.)
Tại sao cần phân định phải liên quan đến mã thông báo và từ vựng .
ksh
vỏ trong câu hỏi. Bash mượn [[
toán tử từ ksh
và trong câu hỏi này hành vi của họ là giống hệt nhau, nhưng tôi sẽ thận trọng với các giả định vì có một số khác biệt đáng kể giữa ksh
và bash
hành vi và nội bộ. Đó chỉ là vì shellcheck hoạt động trên tập lệnh bash, nó có thể không nhất thiết là công cụ thích hợp cho tập lệnh ksh. Chỉ cần một cái gì đó để ghi nhớ trong khi tiếp cận các vỏ khác nhau
[[
quy tắc tích hợp. Tôi không có cách nào suy ra đó ksh
là một cái vỏ shellcheck
có thể tìm thấy lỗi. Tôi hy vọng người khác đánh giá cao ksh
và bash
là hai phiên dịch viên khác nhau. Cảm ơn bạn đã đề cập đến điều đó. Cũng đáng chú ý [[
là một bash được xây dựng trong khi [
là một lệnh bên ngoài.
[
cũng là một bash tích hợp :) manpages.ubfox.com/manpages/bionic/man7/bash-builtins.7.html Nhưng bạn không ở xa - [
hoặc test
được yêu cầu phải là một lệnh bên ngoài. Vào thời của vỏ Bourne ban đầu [
trên thực tế là một lệnh bên ngoài và ngày nay vẫn tồn tại /usr/bin/[
vì POSIX yêu cầu nó phải là một lệnh bên ngoài pubs.opengroup.org/onlinepub/009695399/utilities/test.html Rất ít được POSIX yêu cầu được xây dựng-in pubs.opengroup.org/onlinepubs/009695399/idx/sbi.html Builtin [
là cho hiệu quả
ksh
; sử dụng một hashbang hoặc -s ksh
. Btw, ksh và bash đã [[
"tích hợp sẵn", nhưng đó là một từ khóa , không giống như [
, đó là một phần mềm dựng sẵn . (ksh : whence -v [ [[
; bash type [ [[
:) Các nội trang và các lệnh bên ngoài giống nhau về mặt cú pháp. Một cách [[
khác [
là [[
ngăn chặn một số mở rộng trong các đối số của nó, điều mà nó không thể là một nội dung - nhiều như {
không thể phân nhóm được nó là một nội dung. Đây có thể là lý do tại sao {x
(hoặc [[x
) là một mã thông báo cảm thấy kỳ lạ. Tôi nghĩ thật đúng khi nói nội dung và từ khóa là từ vựng nhưng không giống nhau về mặt cú pháp . @SergiyKolodyazhnyy
[[
có thể là một lệnh bên ngoài! Đó là, nó có thể là một chương trình và không phải là một số cú pháp được hỗ trợ trực tiếp bởi shell của bạn. Có thể hỗ trợ cú pháp không gian trống ksh
nhưng nó sẽ thất bại trên các hệ thống có bên ngoài [[
vì vậy vì lý do tương thích, tốt hơn là giữ không gian cần thiết.
Vì [[-e
có thể tham gia mở rộng vỏ (nó có thể được sử dụng như
echo [[-e]*
để liệt kê tất cả các tệp bắt đầu bằng một chữ cái giữa [
và e
bao gồm), nó sẽ là một mớ hỗn độn nếu [
và ]
là các ký tự đặc biệt không tham gia vào phân tách từ được điều chỉnh bởi khoảng trắng thông thường.
[[
là một từ khóa - có lẽ là cây phân tích của shell yêu cầu các từ khóa phải được phân định bằng khoảng trắng