Sự đơn giản thanh lịch của Bash dường như bị lạc trong trang người đàn ông khổng lồ của nó.
Ngoài các giải pháp tuyệt vời ở trên, tôi nghĩ tôi sẽ cố gắng cung cấp cho bạn một bảng cheat về cách bash phân tích cú pháp và diễn giải các câu lệnh . Sau đó, sử dụng lộ trình này tôi sẽ phân tích các ví dụ được trình bày bởi người hỏi để giúp bạn hiểu rõ hơn lý do tại sao chúng không hoạt động như dự định.
Lưu ý: Dòng script Shell được sử dụng trực tiếp. Các dòng đầu vào được gõ được mở rộng lịch sử đầu tiên.
Mỗi dòng bash được mã hóa đầu tiên hoặc nói cách khác được cắt thành những gì được gọi là mã thông báo . (Mã thông báo xảy ra trước tất cả các bản mở rộng khác, bao gồm dấu ngoặc, dấu ngã, tham số, lệnh, số học, quy trình, tách từ và mở rộng tên tệp.)
Mã thông báo ở đây có nghĩa là một phần của dòng đầu vào được phân tách (được phân tách) bởi một trong các ký tự meta đặc biệt sau:
space, - White space...
tab,
newline,
‘<’, - Redirection & piping...
‘|’,
‘>’
‘&’, - And/Both < | > | >> .or. &<file descriptor>
‘;’, - Command termination
‘(’, - Subshell, closed by - ‘)’
Bash sử dụng nhiều ký tự đặc biệt khác nhưng chỉ 10 cái này tạo ra các mã thông báo ban đầu.
Tuy nhiên vì đôi khi các ký tự meta này đôi khi cũng phải được sử dụng trong mã thông báo, cần có một cách để loại bỏ ý nghĩa đặc biệt của chúng. Điều này được gọi là thoát. Thoát được thực hiện bằng cách trích dẫn một chuỗi một hoặc nhiều ký tự, (ví dụ 'xx..'
, "xx.."
), hoặc bằng cách đặt trước một nhân vật cá nhân với một back-slash, (ví dụ \x
). (Nó phức tạp hơn một chút so với điều này bởi vì các trích dẫn cũng cần được trích dẫn, và vì các trích dẫn kép không trích dẫn mọi thứ, nhưng việc đơn giản hóa này sẽ làm ngay bây giờ.)
Đừng nhầm lẫn trích dẫn bash với ý tưởng trích dẫn một chuỗi văn bản, như trong các ngôn ngữ khác. Những gì ở giữa các dấu ngoặc kép trong bash không phải là các chuỗi, mà là các phần của dòng đầu vào có các ký tự meta được thoát để chúng không phân định mã thông báo.
Lưu ý, có một sự khác biệt quan trọng giữa '
, và "
, nhưng đó là cho một ngày khác.
Các ký tự meta không được giải mã còn lại sau đó trở thành dấu tách mã thông báo.
Ví dụ,
$ echo "x"'y'\g
xyg
$ echo "<"'|'\>
<|>
$ echo x\; echo y
x; echo y
Trong ví dụ đầu tiên, có hai mã thông báo được tạo bởi một dấu phân cách không gian: echo
và xyz
.
Tương tự như vậy trong ví dụ thứ 2.
Trong ví dụ thứ ba dấu chấm phẩy được bỏ trốn, do đó, có 4 thẻ được sản xuất bởi một dấu phân cách không gian, echo
, x;
, echo
, và y
. Mã thông báo đầu tiên sau đó được chạy dưới dạng lệnh và lấy ba mã thông báo tiếp theo làm đầu vào. Lưu ý thứ 2 echo
không được thực thi.
Điều quan trọng cần nhớ là vẻ bề ngoài đầu tiên bash cho các ký tự thoát ( '
, "
và \
), và sau đó tìm kiếm delimiters meta-nhân vật không thoát ra, theo thứ tự đó.
Nếu không thoát thì 10 ký tự đặc biệt này đóng vai trò là token
dấu phân cách. Một số trong số chúng cũng có ý nghĩa bổ sung, nhưng trước hết, chúng là các dấu phân cách mã thông báo.
Những gì grep mong đợi
Trong ví dụ trên grep cần những thẻ, grep
, string
, filename
.
Câu hỏi đầu tiên của câu hỏi là:
$ grep (sau đó | có) xx
Trong trường hợp này (
, )
và |
là nhân vật siêu thoát và để phục vụ để phân chia các đầu vào vào các thẻ: grep
, (
, then
, |
, there
, )
, và x.x
. grep muốn nhìn thấy grep
, then|there
và x.x
.
Lần thử thứ hai của câu hỏi là:
grep "(sau đó | có)" xx
Đây tokenizes vào grep
, (then|there)
, x.x
. Bạn có thể thấy điều này nếu bạn trao đổi grep cho echo:
echo "(sau đó | có)" xx
(sau đó | có) xx