Vỏ POSIX: `$` có mất nghĩa đặc biệt nếu nó là ký tự cuối cùng trong một từ không?


17

Trên tro, gạch ngang và bash, khi tôi chạy

$ echo ab$

nó trở lại

ab$

Đây có phải là hành vi được chỉ định bởi POSIX hay đây chỉ là quy ước phổ biến trong hệ vỏ tương thích POSIX? Tôi không thể tìm thấy bất cứ điều gì trên trang Ngôn ngữ lệnh Shell POSIX có đề cập đến hành vi này.


4
Câu hỏi hay hơn là "Có $ đạt được ý nghĩa đặc biệt nếu đó là ký tự cuối cùng trong một từ không?" Không có ý nghĩa đặc biệt duy nhất được gán cho $; nó được sử dụng để giới thiệu nhiều, nhưng khác biệt, mở rộng, như mở rộng tham số ${...}, thay thế lệnh $(...)và biểu thức số học $((...)). Một số shell giới thiệu các bối cảnh bổ sung, như kshbiến thể thay thế lệnh x=${ echo foo; echo bar;}(khác với tiêu chuẩn $(...)bằng cách không thực hiện các lệnh trong một lớp con).
chepner

@chepner Bạn có quan tâm để cân nhắc về sự khác biệt về quan điểm giữa Issac và Michael Homer không? Câu trả lời của họ rõ ràng mâu thuẫn với nhau
Harold Fischer

1
Tôi đồng ý với cách giải thích của Michael Homer; Shell thậm chí không bắt đầu lo lắng về việc mở rộng cho đến khi hoàn thành phân tích cú pháp, do đó, trong một từ duy nhất ab$, không có ký tự nào theo sau $, cho dù nó được "theo dõi" bởi một ký tự null trong chuỗi đầu vào ban đầu hay khoảng trắng trong một trường hợp thích echo ab$ foo; khoảng trắng không trích dẫn ban đầu đã được nhận ra và loại bỏ sau khi phân tích cú pháp.
chepner

Câu trả lời:


10

$bản thân nó không có ý nghĩa đặc biệt echo $, chỉ khi kết hợp với nhân vật khác sau nó và tạo thành một bản mở rộng, ví dụ $var(hoặc ${var}) $(util), $((1+2)).

Các $nhận nó "đặc biệt" có nghĩa là xác định sự mở rộng trong tiêu chuẩn POSIX dưới phần Mã Recognition :

Nếu ký tự hiện tại là không được trích dẫn $hoặc `, shell sẽ xác định bắt đầu của bất kỳ ứng cử viên nào để mở rộng tham số, thay thế lệnh hoặc mở rộng số học từ các chuỗi ký tự không được trích dẫn giới thiệu của chúng: $hoặc ${, $(hoặc `, và $((, tương ứng. Shell sẽ đọc đủ đầu vào để xác định phần cuối của đơn vị sẽ được mở rộng ( như được giải thích trong phần được trích dẫn). Trong khi xử lý các ký tự, nếu các trường hợp mở rộng hoặc trích dẫn được tìm thấy lồng trong thay thế, shell sẽ xử lý đệ quy chúng theo cách được chỉ định cho cấu trúc được tìm thấy. Các ký tự được tìm thấy từ đầu thay thế đến cuối của nó, cho phép mọi đệ quy cần thiết để nhận ra các cấu trúc nhúng, sẽ được đưa vào không được sửa đổi trong mã thông báo kết quả, bao gồm mọi toán tử thay thế được nhúng hoặc kèm theo. Mã thông báo sẽ không được phân định vào cuối thay thế.

Vì vậy, nếu $không hình thành một bản mở rộng, các quy tắc phân tích cú pháp khác có hiệu lực:

Nếu ký tự trước là một phần của từ, ký tự hiện tại sẽ được thêm vào từ đó.

Điều đó bao gồm ab$chuỗi của bạn .

Trong trường hợp của một mình $("từ mới" sẽ là $chính nó):

Ký tự hiện tại được sử dụng làm bắt đầu của một từ mới.

Các ý nghĩa của từ này tạo ra có chứa một $đó là không phải là một sự mở rộng tiêu chuẩn được một cách rõ ràng định nghĩa là không xác định bởi POSIX.

Cũng lưu ý rằng đó $là ký tự cuối cùng $$, nhưng đây cũng là biến chứa PID của shell hiện tại. Trong bash, !$có thể gọi một mở rộng lịch sử (đối số cuối cùng af lệnh trước đó). Vì vậy, nói chung, không, $không phải là không có nghĩa ở cuối của một từ không được trích dẫn, nhưng ở cuối của một từ, nó ít nhất không biểu thị một sự mở rộng tiêu chuẩn.


7

Tùy thuộc vào tình huống chính xác, điều này là không xác định rõ ràng (vì vậy việc triển khai có thể làm như họ muốn) hoặc bắt buộc phải xảy ra như bạn quan sát. Trong kịch bản chính xác của bạn echo ab$, POSIX bắt buộc đầu ra "ab $" mà bạn quan sát thấynó không phải là không xác định . Một bản tóm tắt nhanh chóng của tất cả các trường hợp khác nhau là ở cuối.

Có hai yếu tố: đầu tiên mã thông báo thành các từ và sau đó giải thích các từ đó.


Mã thông báo

POSIX tokenisation đòi hỏi một $đó không phải là sự bắt đầu của một giá trị mở rộng tham số , thay thế lệnh , hoặc thay số học được coi là một phần đen của WORDcon người dấu hiệu xây dựng. Điều này là do quy tắc 5 ("Nếu ký tự hiện tại là không được trích dẫn $hoặc `, trình bao sẽ xác định bắt đầu của bất kỳ ứng cử viên nào để mở rộng tham số, thay thế lệnh hoặc mở rộng số học từ các chuỗi ký tự không được trích dẫn giới thiệu của chúng: $hoặc ${, $(hoặc `, và $((, tương ứng" ) không áp dụng, vì không có bất kỳ mở rộng nào là khả thi ở đó. Mở rộng tham số yêu cầu một tên hợp lệ xuất hiện ở đó và một tên trống không hợp lệ.

Vì quy tắc này không được áp dụng, chúng tôi tiếp tục theo dõi cho đến khi tìm thấy quy tắc đó. Hai ứng cử viên là # 8 ("Nếu ký tự trước là một phần của từ, ký tự hiện tại sẽ được thêm vào từ đó.") Và # 10 ("Ký tự hiện tại được sử dụng làm từ bắt đầu của một từ mới.") , áp dụng cho echo a$echo $tương ứng.

Ngoài ra còn có trường hợp thứ ba của biểu mẫu echo a$+brơi vào cùng vết nứt, vì đó +không phải là tên của một tham số đặc biệt. Cái này chúng ta sẽ quay lại sau, vì nó kích hoạt các phần khác nhau của quy tắc.

Do đó, đặc điểm kỹ thuật yêu cầu rằng $được coi là một phần của từ cú pháp, và sau đó nó có thể được xử lý thêm sau này.


Mở rộng từ

Sau khi đầu vào được phân tích cú pháp theo cách này, với từ được $bao gồm trong từ, mở rộng từ được áp dụng cho từng từ đã được đọc. Mỗi từ được xử lý riêng .

Nó được chỉ định rằng :

Nếu một '$' không được trích dẫn được theo sau bởi một ký tự không phải là một trong những điều sau đây:

  • Một ký tự số
  • Tên của một trong các tham số đặc biệt (xem Thông số đặc biệt )
  • Một ký tự đầu tiên hợp lệ của một tên biến
  • A <left-curly-bracket>('{')
  • Một <left-parenthesis>

kết quả là không xác định.

"Không xác định" là một thuật ngữ cụ thể ở đây có nghĩa là

  1. Một vỏ phù hợp có thể chọn bất kỳ hành vi nào trong trường hợp này
  2. Một ứng dụng phù hợp không thể dựa vào bất kỳ hành vi cụ thể nào

Trong ví dụ của bạn, echo ab$thì $ không được theo sau bởi bất kỳ nhân vật , vì vậy quy định này không áp dụng và kết quả không xác định không gọi. Đơn giản là không có sự mở rộng nào được kích hoạt bởi $, vì vậy nó thực sự có mặt và được in ra.

Trường hợp sẽ áp dụng là trong trường hợp thứ ba của chúng tôi từ trên : echo a$+b. Dưới đây $là tiếp theo +, mà không phải là một con số, tham số đặc biệt ( @, *, #, ?, -, $, !, hay 0), hãy bắt đầu của một biến tên (gạch dưới hoặc một chữ cái từ bộ ký tự xách tay ), hoặc một trong các dấu ngoặc đơn. Trong trường hợp này, hành vi không được chỉ định: vỏ tuân thủ được phép phát minh ra một tham số đặc biệt được gọi là +mở rộng và ứng dụng tuân thủ không nên cho rằng vỏ không có . Shell có thể làm bất cứ điều gì khác mà nó thích, bao gồm báo cáo lỗi.

Ví dụ: zsh, bao gồm trong chế độ POSIX của nó, diễn giải $+blà "được bđặt biến " và thay thế 1 hoặc 0 ở vị trí của nó. Nó tương tự có phần mở rộng cho ~=. Đây là hành vi phù hợp.

Một nơi khác điều này có thể xảy ra là echo "a$ b". Một lần nữa, shell được phép làm theo ý muốn và bạn với tư cách là tác giả kịch bản sẽ thoát khỏi $nếu bạn muốn đầu ra theo nghĩa đen. Nếu bạn không, nó có thể hoạt động, nhưng bạn không thể dựa vào nó. Đây là chữ cái tuyệt đối của đặc tả, nhưng tôi không nghĩ loại chi tiết này được dự định hoặc xem xét.


Tóm tắt

  • echo ab$: đầu ra theo nghĩa đen, được chỉ định đầy đủ
  • echo a$ b: đầu ra theo nghĩa đen, được chỉ định đầy đủ
  • echo a$ b$: đầu ra theo nghĩa đen, được chỉ định đầy đủ
  • echo a$b: mở rộng tham số b, được chỉ định đầy đủ
  • echo a$-b: mở rộng tham số đặc biệt -, được chỉ định đầy đủ
  • echo a$+b: hành vi không xác định
  • echo "a$ b": hành vi không xác định

Đối với $phần cuối của một từ, bạn được phép dựa vào hành vi và nó phải được xử lý theo nghĩa đen và được truyền cho echolệnh như một phần của đối số. Đó là một yêu cầu phù hợp trên vỏ.


Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
terdon

@MichaelHomer echo $cũng sẽ được hiểu theo nghĩa đen và đầy đủ?
Harold Fischer

@HaroldFischer Có
Michael Homer

Nơi nào làm echo "$"echo "a b$"rơi?
Harold Fischer
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.