Sự khác biệt giữa các giá trị ăn vặt, '' ',' '' và $


49

Đôi khi tôi thấy kịch bản sử dụng tất cả các cách khác nhau để trích dẫn một số văn bản: "...", '...', $'...', và $"...". Tại sao có rất nhiều loại trích dẫn khác nhau đang được sử dụng?

Họ có cư xử khác nhau hay ảnh hưởng đến những gì tôi có thể làm bên trong họ không?


1
Có thể trùng lặp chéo trang web. Câu trả lời này cung cấp một bản tóm tắt (hoặc liên kết đến) ngữ nghĩa của tất cả các loại trích dẫn khác nhau.
chepner

Câu trả lời:


66

Tất cả những điều này có nghĩa là một cái gì đó khác nhau, và bạn có thể viết những thứ khác nhau bên trong chúng (hoặc những điều tương tự, với ý nghĩa khác nhau). Các loại trích dẫn khác nhau diễn giải các chuỗi thoát khác nhau bên trong chúng ( \something), hoặc làm hoặc không cho phép nội suy biến đổi ( $something) và các loại mở rộng khác bên trong chúng.

Nói ngắn gọn:

  • '...' là hoàn toàn theo nghĩa đen.
  • "..." cho phép cả biến và ký tự trích dẫn nhúng.
  • $'...'thực hiện thoát ký tự như thế \n, nhưng không mở rộng biến.
  • $"..." dành cho các bản dịch ngôn ngữ của con người trong Bash và ksh.

'Dấu nháy đơn'

Bất cứ điều gì bạn viết giữa các trích dẫn đều được xử lý theo nghĩa đen và không được xử lý. Dấu gạch chéo ngược và ký hiệu đô la không có ý nghĩa đặc biệt ở đó. Điều này có nghĩa là bạn không thể gạch chéo ngược - thoát một ký tự (bao gồm cả các dấu ngoặc đơn khác!), Nội suy một biến hoặc sử dụng bất kỳ tính năng shell nào khác.

Tất cả các ví dụ này dẫn đến kết quả là những gì được viết giữa các trích dẫn:

'hello world'                     => hello world
'/pkg/bin:$PATH'                  => /pkg/bin:$PATH
'hello\nworld'                    => hello\nworld
'`echo abc`'                      => `echo abc`
'I\'dn\'t've'                     => I\dn'tve

Chuỗi cuối cùng rất phức tạp - có hai chuỗi trích dẫn đơn chạy cùng với một số văn bản không trích dẫn. Cái đầu tiên chứa I\. Văn bản không được trích dẫn dn\'tchứa một trích dẫn duy nhất được thoát ở cấp độ vỏ , do đó, nó không bắt đầu một chuỗi trích dẫn và được bao gồm dưới dạng một ký tự bằng chữ (vì vậy, dn't). Chuỗi trích dẫn cuối cùng là chỉ ve. Tất cả những thứ đó được chạy cùng nhau thành một từ theo cách thông thường mà vỏ hoạt động.

Một thành ngữ khá phổ biến để kết hợp văn bản và biến văn bản là chạy chúng cùng nhau như thế:

'let x="'$PATH\"

sẽ cho kết quả

let x="/usr/bin:/bin"

dưới dạng một từ duy nhất (tốt hơn $PATHlà trích dẫn kép trong trường hợp - khoảng trắng hoặc ký tự toàn cầu trong giá trị biến có thể được xử lý theo cách khác - nhưng vì lợi ích của một ví dụ đang chạy mà tôi không thể đọc được).


"Dấu ngoặc kép"

Bên trong dấu ngoặc kép, hai loại mở rộng được xử lý và bạn có thể sử dụng dấu gạch chéo ngược để thoát ký tự để ngăn chặn việc mở rộng hoặc thoát khỏi bị xử lý.

Có hai loại mở rộng xảy ra bên trong dấu ngoặc kép:

Trong dấu ngoặc kép, dấu gạch chéo ngược có thể ức chế những mở rộng đó bằng cách đặt nó trước $hoặc `. Nó cũng có thể thoát khỏi trích dẫn kép, do đó, \"chỉ bao gồm "trong chuỗi của bạn hoặc dấu gạch chéo ngược khác. Bất kỳ dấu gạch chéo ngược nào khác được giữ nguyên theo nghĩa đen - không có lối thoát nào để tạo các ký tự khác và nó không bị xóa.

Một số ví dụ này hoạt động khác với trước đây và một số thì không:

"hello world"                     => hello world
"/pkg/bin:$PATH"                  => /pkg/bin:/bin:/usr/bin
"hello\nworld"                    => hello\nworld
"hello\\nworld"                   => hello\nworld
"`echo abc`"                      => abc
"I\'dn\'t've"                     => I\'dn\'t've
"I'dn't've"                       => I'dn't've
"I\"dn\"t've"                     => I"dn"t've

$ 'Trích dẫn ANSI-C'

Kiểu trích dẫn này cho phép thoát dấu gạch chéo kiểu C được xử lý, nhưng không được nhúng biến hoặc thay thế. Đó là loại trích dẫn duy nhất hỗ trợ nhân vật trốn thoát .

Đây là một phần mở rộng từ ksh, hiện được hỗ trợ trong Bash, zsh và một số shell khác. Nó không phải là chưa là một phần của tiêu chuẩn POSIX và các kịch bản để tối đa-di không thể sử dụng nó, nhưng một Bash hoặc ksh kịch bản là miễn phí để.

Tất cả những thoát có thể được sử dụng với ý nghĩa C của họ: \a, \b, \f, \n, \r, \t, \v, và thoát theo nghĩa đen \\, \', \", và \?. Chúng cũng hỗ trợ các phần mở rộng \e(ký tự thoát) và trong Bash và ksh \cx(những gì sẽ được nhập bởi Ctrl-x , ví dụ: \cMtrả về vận chuyển). Shell có một loạt các phần mở rộng nhỏ của riêng họ.

Nó cũng cho phép bốn loại thoát nhân vật chung:

  • \nnn, một byte đơn có giá trị bát phân nnn
  • \xHH, một byte đơn với giá trị thập lục phân HH
  • \uHHHH, bảng mã Unicode có chỉ số thập lục phân là HHHH
  • \UHHHHHHHH, bảng mã Unicode có chỉ số thập lục phân là HHHHHHHH

Tất cả các chữ số đó là tùy chọn sau cái đầu tiên.

$`không có ý nghĩa và được bảo tồn theo nghĩa đen, vì vậy bạn không thể bao gồm một biến ở đó.

$'hello world'                    => hello world
$'/pkg/bin:$PATH'                 => /pkg/bin:$PATH
$'hello\nworld'                   => hello
                                     world
$'`echo abc`'                     => `echo abc`
$'I\'dn\'t\'ve'                   => I'dn't've
$'\U1f574\u263A'                  => 🕴☺

Hầu hết các thoát bạn có thể mô phỏng sử dụng các printflệnh , mặc dù POSIX chỉ yêu cầu \\, \a, \b, \f, \n, \r, \t, \v, và \nnnlàm việc ở đó. Bạn có thể sử dụng thay thế lệnh để nhúng printfdấu ngoặc kép bên trong nếu cần : "Path:$(printf '\t')$PATH".


$ "Bản dịch địa phương"

Đây là một phần mở rộng dành riêng cho ksh và Bash để bản địa hóa các chuỗi văn bản ngôn ngữ tự nhiên và tìm kiếm phần bên trong các trích dẫn trong một danh mục tin nhắn. Nó thực hiện tất cả các mở rộng trích dẫn đôi đầu tiên. Nếu chuỗi không được tìm thấy trong cơ sở dữ liệu dịch, nó được sử dụng làm bản dịch riêng. Giả định tích hợp là các chuỗi bằng tiếng Anh.

Bạn có thể không muốn sử dụng cái này, nhưng nếu bạn thấy nó, bạn thường có thể coi nó là dấu ngoặc kép thông thường.


Một điểm lưu ý là không có loại trích dẫn nào cho phép cả mở rộng tham số nhúng và thoát ký tự nhúng. Trong hầu hết các trường hợp bạn muốn điều đó, bạn sẽ tốt hơn (an toàn hơn) bằng cách sử dụng printf:

printf 'New path: \e[1m%s\e[0m' "/pkg/bin:$PATH:"

Điều này phân tách rõ ràng phần nào là đối tượng thoát ký tự và phần nào là giá trị dữ liệu.

Một điều nữa là tất cả các kiểu trích dẫn này tạo ra một "từ" trong vỏ, trừ khi $@ hoặc mở rộng mảng ${x[@]}được sử dụng bên trong dấu ngoặc kép. Cả hai hình thức trích dẫn luôn luôn là một từ và không bao giờ mở rộng thêm nữa.


$"..."cũng từ ksh93, được thêm vào bash trong 2.0.
Stéphane Chazelas

Không có \cXtrong zsh. Nó \CXhoặc \C-Xở đó ( \cđã có một ý nghĩa đặc biệt trong echo)
Stéphane Chazelas

'let x="'$PATH\"là sai trong bối cảnh danh sách trong các shell khác với zshnhư $PATHkhông được trích dẫn (vì vậy sẽ có thể bị phân tách + toàn cầu mà bạn không muốn ở đây).
Stéphane Chazelas

Bạn có thể muốn làm rõ rằng bạn đang nói về vỏ giống như Korn, cách xử lý trích dẫn khác nhau ở csh, RC, cá ...
Stéphane Chazelas

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.