Trong câu hỏi này, một người nào đó báo cáo sự cố khi sử dụng tài liệu ở đây với một từ phân cách được trích dẫn bên trong $(...)
thay thế lệnh , trong đó dấu gạch chéo ngược \
ở cuối dòng bên trong tài liệu kích hoạt tiếp tục dòng nối dòng mới , trong khi đó tài liệu bên ngoài thay thế lệnh hoạt động như mong đợi .
Đây là một tài liệu ví dụ đơn giản:
cat <<'EOT'
abc ` def
ghi \
jkl
EOT
Điều này bao gồm một backtick và một dấu gạch chéo ngược ở cuối dòng. Dấu phân cách được trích dẫn, vì vậy không có sự mở rộng nào xảy ra bên trong cơ thể. Trong tất cả các Bourne-alike tôi có thể tìm thấy kết quả này nguyên văn nội dung. Nếu tôi đặt cùng một tài liệu bên trong lệnh thay thế như sau:
x=$(cat <<'EOT'
abc ` def
ghi \
jkl
EOT
)
echo "$x"
sau đó họ không còn cư xử giống hệt nhau:
dash
,ash
,zsh
,ksh93
, BusyBoxash
,mksh
và SunOS 5.10 POSIXsh
tất cả các cung cấp cho các nội dung nguyên văn của tài liệu, như trước đây.- Bash 3.2 đưa ra một lỗi cú pháp cho một backtick chưa từng có. Với backticks phù hợp, nó cố gắng chạy nội dung dưới dạng một lệnh.
- Bash 4.3 thu gọn "ghi" và "jkl" vào một dòng, nhưng không có lỗi. Các
--posix
tùy chọn không ảnh hưởng này. Kusalananda nói với tôi (cảm ơn!) Hànhpdksh
xử theo cùng một cách .
Trong câu hỏi ban đầu, tôi đã nói rằng đây là một lỗi trong trình phân tích cú pháp của Bash. Là nó? [Cập nhật: có ] Văn bản có liên quan từ POSIX (tất cả từ định nghĩa Ngôn ngữ lệnh Shell) mà tôi có thể tìm thấy là:
- §2.6.3 Thay thế lệnh :
Với biểu mẫu $ (lệnh), tất cả các ký tự theo dấu ngoặc đơn mở cho dấu ngoặc đơn đóng phù hợp sẽ tạo thành lệnh. Bất kỳ tập lệnh shell hợp lệ nào cũng có thể được sử dụng cho lệnh , ngoại trừ tập lệnh chỉ bao gồm các chuyển hướng tạo ra kết quả không xác định.
- §2.7.4 Dưới đây - Tài liệu :
Nếu bất kỳ phần nào của từ được trích dẫn, dấu phân cách sẽ được hình thành bằng cách thực hiện loại bỏ trích dẫn trên từ và các dòng tài liệu ở đây sẽ không được mở rộng.
- §2.2.1 Ký tự thoát (Dấu gạch chéo ngược) :
Nếu <newline> tuân theo <dấu gạch chéo ngược>, trình bao sẽ hiểu điều này là tiếp tục dòng. <Backslash> và <newline> sẽ bị xóa trước khi chia đầu vào thành các mã thông báo.
- §2.3 Nhận dạng mã thông báo :
Khi mã thông báo io_here đã được ngữ pháp nhận ra (xem Ngữ pháp Shell ), một hoặc nhiều dòng tiếp theo ngay sau mã thông báo NEWLINE tiếp theo tạo thành cơ thể của một hoặc nhiều tài liệu ở đây và sẽ được phân tích cú pháp theo các quy tắc tại đây- Tài liệu .
Khi nó không xử lý io_here , shell sẽ phá vỡ đầu vào của nó thành các mã thông báo bằng cách áp dụng quy tắc áp dụng đầu tiên bên dưới cho ký tự tiếp theo trong đầu vào của nó. ...
...
- Nếu ký tự hiện tại là <backslash>, trích dẫn đơn hoặc trích dẫn kép và nó không được trích dẫn, nó sẽ ảnh hưởng đến trích dẫn cho các ký tự tiếp theo cho đến cuối văn bản được trích dẫn. Các quy tắc để trích dẫn được mô tả trong Trích dẫn . Trong quá trình nhận dạng mã thông báo, không có sự thay thế nào thực sự được thực hiện và mã thông báo kết quả sẽ chứa chính xác các ký tự xuất hiện trong đầu vào (ngoại trừ tham gia <newline>), không được sửa đổi, bao gồm mọi trích dẫn được nhúng hoặc kèm theo hoặc giữa các toán tử thay thế, giữa và cuối của văn bản trích dẫn.
Giải thích của tôi về điều này là tất cả các nhân vật sau $(
khi kết thúc )
bao gồm tập lệnh shell, nguyên văn; một tài liệu ở đây xuất hiện, vì vậy ở đây - quá trình xử lý tài liệu xảy ra thay vì mã thông báo thông thường; tài liệu ở đây sau đó có một dấu phân cách được trích dẫn, có nghĩa là nội dung của nó được xử lý nguyên văn; và nhân vật thoát không bao giờ đi vào nó. Tôi có thể thấy một đối số, tuy nhiên, trường hợp này đơn giản là không được giải quyết và cả hai hành vi đều được cho phép. Có thể tôi cũng đã bỏ qua một số văn bản có liên quan ở đâu đó.
- Là tình huống này được làm rõ ràng hơn ở nơi khác?
- Một kịch bản di động nên có thể dựa vào (về lý thuyết) là gì?
- Là điều trị cụ thể được đưa ra bởi bất kỳ trong số các vỏ này (Bash 3.2 / Bash 4.3 / mọi người khác) có bắt buộc theo tiêu chuẩn không? Cấm? Được phép?
echo "$x"
, nhưng bất kỳ cách nào để kiểm tra biến đều hoạt động. Tôi đã chỉnh sửa dòng đó vào dưới cùng.
$(...)
bằng bất cứ thứ gì mà đầu ra là ... Bây giờ, khi chạy lệnh trong ví dụ của bạn trong một lớp con (in bash
), nó sẽ tạo ra kết quả mong đợi. Chỉ khi biến nó thành sự thay thế lệnh thì nó mới thu gọn "ghi" và "jkl". Vì vậy, đây là một lỗi imo