trích dẫn lồng nhau trong một lót được bình chọn cao


20

Câu trả lời của StackOverflow với> 3,5K phiếu có tính năng một lớp này để gán cho DIRthư mục của tập lệnh bash hiện tại:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

Tôi bối rối bởi các trích dẫn kép lồng nhau. Theo như tôi có thể nói, các đoạn sau đây được trích dẫn hai lần:

"$( cd "
"${BASH_SOURCE[0]}"
" && pwd )"

... và mọi thứ khác ở bên phải của =(tức là $( dirname)) không được trích dẫn. Nói cách khác, tôi giả sử rằng các ký tự thứ 2, 4 và 6 lần lượt ""đóng" các ký tự thứ 1, 3 và 5 ".

Tôi hiểu những gì trích dẫn kép "${BASH_SOURCE[0]}"đạt được, nhưng mục đích của hai cặp trích dẫn kia là gì?

Mặt khác, nếu (và điểm số phiếu cao mặc dù), đoạn trích trên là không chính xác, cách nào đúng để đạt được ý định danh nghĩa của nó?

(Theo ý nghĩa danh nghĩa, ý tôi là: thu thập giá trị được trả về pwdsau lần đầu tiên cdvào thư mục được trả về bởi dirname "${BASH_SOURCE[0]}"và thực hiện cd-ing trong một vỏ con, sao cho $PWDvỏ cha mẹ không thay đổi).


1
đó là vì một tính năng của $ (...) : $( here, it's a subshell, but you are writing code as if you were writing it on the "first level" of the shell .... ).
Olivier Dulac

Tôi đến đây vì kịch bản cài đặt docker. Để tìm tên của bản phân phối:lsb_dist="$(. /etc/os-release && echo "$ID")"; echo "$lsb_dist"
David Tonhofer

Lưu ý rằng không gian trong dòng là không cần thiết: cũng DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"hoạt động.
David Tonhofer

Câu trả lời:


12

Câu đố của bạn không đúng về cách bash(và vỏ nói chung) phân tích cú pháp đầu vào. Trong:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

Đầu tiên, bashphân tích phía bên phải của phép gán thành một chuỗi dài $( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )dấu ngoặc kép có thể xuất hiện bên trong dấu ngoặc kép .

Sau đó, bashbắt đầu phân tích cú pháp thay thế lệnh. Bởi vì tất cả các ký tự theo dấu ngoặc đơn mở để kèm theo dấu ngoặc đơn được sử dụng để xây dựng lệnh bên trong thay thế lệnh, bạn sẽ nhận được:

cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd

Shell tiếp tục phân tích cú pháp lệnh ghép đó, chia nó thành hai phần:

  • cd "$( dirname "${BASH_SOURCE[0]}" )"
  • pwd

Sau đó, áp dụng quy tắc phân tích cú pháp tương tự cho cd "$( dirname "${BASH_SOURCE[0]}" )", nhưng lần này, dấu ngoặc kép không thừa, nhưng có ý nghĩa. Chúng ngăn chặn sự phân tách trường do kết quả $( dirname "${BASH_SOURCE[0]}" )và cả việc mở rộng ${BASH_SOURCE[0]}(Ngược lại với dấu ngoặc kép ngoài cùng nhất, sẽ không cần thiết trong RHS của phép gán biến để ngăn chặnsplit+glob ).


Quy tắc này áp dụng cho thay thế lệnh trong tất cả các vỏ POSIX . Một câu đố chi tiết hơn mà bạn có thể đọc trong phần Nhận dạng mã thông báo của thông số POSIX .


21

Khi một trong những bên trong $(...), trích dẫn bắt đầu lại từ đầu.

Nói cách khác, "..."$(...)có thể lồng vào nhau. Quá trình thay thế, $(...)có thể chứa một hoặc nhiều chuỗi trích dẫn hoàn chỉnh . Ngoài ra, các chuỗi trích dẫn kép có thể chứa một hoặc nhiều thay thế quy trình hoàn chỉnh . Nhưng, họ không xen kẽ. Do đó, một chuỗi trích dẫn kép bắt đầu bên trong một sự thay thế quá trình sẽ không bao giờ mở rộng ra bên ngoài nó hoặc ngược lại.

Vì vậy, hãy xem xét:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

Bên trong bên trong $(...)là:

dirname "${BASH_SOURCE[0]}"

Trong phần trên ${BASH_SOURCE[0]}là trích dẫn kép. Bất kỳ trích dẫn nào, gấp đôi hoặc đơn, bên ngoài $(...)đều không liên quan khi xác định đó ${BASH_SOURCE[0]}là trích dẫn kép.

Bên ngoài $(...)chứa:

cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd

Ở đây, biểu thức $( dirname "${BASH_SOURCE[0]}" )được trích dẫn kép. Thực tế là có những trích dẫn bên ngoài $(...)là không liên quan khi xem xét những gì bên trong nó. Thực tế là có những trích dẫn bên trong nội tâm $(...)cũng không liên quan.

Đây là cách các dấu ngoặc kép khớp với nhau:

nhập mô tả hình ảnh ở đây


Ý bạn là irrelevantgì Ngoại trừ hầu hết các dấu ngoặc đơn bên ngoài, tất cả những cái khác có ý nghĩa riêng của nó.
cuonglm

4
Và, đây là lý do tại sao bạn không nên sử dụng backticks: Các quy tắc trích dẫn cực kỳ kỳ lạ và không trực quan.
tự đại diện

Câu nói $(...)liên kết chặt chẽ hơn "..."câu không có ý nghĩa. Chúng không phải là toán tử trộn lẫn và không có thứ bậc giữa chúng (nếu có thì điều đó có nghĩa là dấu ngoặc kép không thể nằm trong dấu ngoặc đơn hoặc dấu ngoặc đơn không thể nằm trong dấu ngoặc kép, nhưng đó không phải là trường hợp). Thuật ngữ kỹ thuật là đó $(…)"…"tổ.
Gilles 'SO- ngừng trở nên xấu xa'

@Gilles Rất tốt. Tôi chỉ nói lại với hy vọng nắm bắt khái niệm tốt hơn.
John1024
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.