Sự khác biệt giữa dấu ngoặc đơn và dấu ngoặc kép trong Bash


Câu trả lời:


579

Dấu ngoặc đơn sẽ không nội suy bất cứ điều gì, nhưng dấu ngoặc kép sẽ. Ví dụ: biến, backticks, \thoát nhất định , v.v.

Thí dụ:

$ echo "$(echo "upg")"
upg
$ echo '$(echo "upg")'
$(echo "upg")

Hướng dẫn Bash có điều này để nói:

3.1.2.2 Báo giá đơn

Các ký tự kèm theo trong dấu ngoặc đơn ( ') giữ nguyên giá trị bằng chữ của mỗi ký tự trong dấu ngoặc kép. Một trích dẫn có thể không xảy ra giữa các trích dẫn đơn, ngay cả khi trước dấu gạch chéo ngược.

3.1.2.3 Báo giá kép

Kèm theo ký tự trong dấu ngoặc kép ( ") giữ gìn giá trị văn chương của tất cả các ký tự trong dấu ngoặc kép, với ngoại lệ của $, `, \, và, khi mở rộng lịch sử được kích hoạt, !. Các ký tự $`giữ lại ý nghĩa đặc biệt của chúng trong dấu ngoặc kép (xem Mở rộng Shell ). Các dấu chéo ngược vẫn giữ được ý nghĩa đặc biệt của nó chỉ khi theo sau là một trong những nhân vật sau: $, `, ",\hoặc dòng mới. Trong dấu ngoặc kép, dấu gạch chéo ngược được theo sau bởi một trong các ký tự này sẽ bị xóa. Dấu gạch chéo ngược trước các ký tự không có ý nghĩa đặc biệt sẽ không được sửa đổi. Một trích dẫn kép có thể được trích dẫn trong dấu ngoặc kép bằng cách đặt trước nó bằng dấu gạch chéo ngược. Nếu được bật, mở rộng lịch sử sẽ được thực hiện trừ khi !xuất hiện trong dấu ngoặc kép được sử dụng dấu gạch chéo ngược. Dấu gạch chéo ngược trước !không được loại bỏ.

Các tham số đặc biệt *@có ý nghĩa đặc biệt khi trong dấu ngoặc kép (xem Mở rộng tham số Shell ).


41
Đối với bất kỳ ai không biết "nội suy" nghĩa là gì: en.wikipedia.org/wiki/String_interpolation
Kolob Canyon

Điều gì về khi bạn đang sử dụng một git_promptgit cung cấp họ đề nghị sử dụng nó như thế này PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ ', nhắc nhở git , theo điều này không nên làm việc. Có điều gì đặc biệt về các PS#biến? hoặc tại sao nó hoạt động nếu nó không thực hiện phép nội suy.
ekiim

@ekiim Văn bản chính xác đó được đặt (không thay đổi) thành PS1. Hãy thử echo $PS1xem tôi muốn nói gì Nhưng PS1được đánh giá trước khi được hiển thị (xem PROMPTINGphần trong trang bash). Để kiểm tra điều này, hãy thử PS1='$X'. Bạn sẽ không có lời nhắc. Sau đó chạy X=foovà đột nhiên lời nhắc của bạn là "foo" (đã PS1được đánh giá khi được đặt thay vì hiển thị, bạn vẫn không có dấu nhắc).
Adam Batkin

262

Các câu trả lời được chấp nhận là rất tốt. Tôi đang làm một bảng giúp hiểu nhanh về chủ đề này. Giải thích liên quan đến một biến đơn giản acũng như một mảng được lập chỉ mục arr.

Nếu chúng ta đặt

a=apple      # a simple variable
arr=(apple)  # an indexed array with a single element

và sau đó echobiểu thức trong cột thứ hai, chúng ta sẽ nhận được kết quả / hành vi được hiển thị trong cột thứ ba. Cột thứ tư giải thích hành vi.

 # | Expression  | Result      | Comments
---+-------------+-------------+--------------------------------------------------------------------
 1 | "$a"        | apple       | variables are expanded inside ""
 2 | '$a'        | $a          | variables are not expanded inside ''
 3 | "'$a'"      | 'apple'     | '' has no special meaning inside ""
 4 | '"$a"'      | "$a"        | "" is treated literally inside ''
 5 | '\''        | **invalid** | can not escape a ' within ''; use "'" or $'\'' (ANSI-C quoting)
 6 | "red$arocks"| red         | $arocks does not expand $a; use ${a}rocks to preserve $a
 7 | "redapple$" | redapple$   | $ followed by no variable name evaluates to $
 8 | '\"'        | \"          | \ has no special meaning inside ''
 9 | "\'"        | \'          | \' is interpreted inside "" but has no significance for '
10 | "\""        | "           | \" is interpreted inside ""
11 | "*"         | *           | glob does not work inside "" or ''
12 | "\t\n"      | \t\n        | \t and \n have no special meaning inside "" or ''; use ANSI-C quoting
13 | "`echo hi`" | hi          | `` and $() are evaluated inside ""
14 | '`echo hi`' | `echo hi`   | `` and $() are not evaluated inside ''
15 | '${arr[0]}' | ${arr[0]}   | array access not possible inside ''
16 | "${arr[0]}" | apple       | array access works inside ""
17 | $'$a\''     | $a'         | single quotes can be escaped inside ANSI-C quoting
18 | "$'\t'"     | $'\t'       | ANSI-C quoting is not interpreted inside ""
19 | '!cmd'      | !cmd        | history expansion character '!' is ignored inside ''
20 | "!cmd"      | cmd args    | expands to the most recent command matching "cmd"
21 | $'!cmd'     | !cmd        | history expansion character '!' is ignored inside ANSI-C quotes
---+-------------+-------------+--------------------------------------------------------------------

Xem thêm:


1
Câu trả lời được chấp nhận nói cuối cùng, The special parameters * and @ have special meaning when in double quotesvậy "*"kết quả *thế nào?
anddero

2
@ Karl-AnderoMere, vì chúng không được mở rộng như các tham số trong trường hợp đó. "$@""$*"là mở rộng tham số. "@""*"không.
Charles Duffy

@CharlesDuffy Cảm ơn, nó có ý nghĩa ngay bây giờ!
anddero

3
Số 9 echo "\'", trả lại cho tôi \'.
MaxGyver

@MaxGyver: cảm ơn bạn đã chỉ nó. Tôi đã cập nhật câu trả lời.
tiền mã hóa

233

Nếu bạn đang đề cập đến những gì xảy ra khi bạn lặp lại một cái gì đó, các dấu ngoặc đơn sẽ lặp lại theo nghĩa đen những gì bạn có giữa chúng, trong khi dấu ngoặc kép sẽ đánh giá các biến giữa chúng và đưa ra giá trị của biến.

Ví dụ, cái này

#!/bin/sh
MYVAR=sometext
echo "double quotes gives you $MYVAR"
echo 'single quotes gives you $MYVAR'

sẽ đưa ra điều này:

double quotes gives you sometext
single quotes gives you $MYVAR

11

Những người khác giải thích rất tốt và chỉ muốn đưa ra với các ví dụ đơn giản.

Dấu ngoặc đơn có thể được sử dụng xung quanh văn bản để ngăn shell diễn giải bất kỳ ký tự đặc biệt nào. Dấu đô la, dấu cách, ký hiệu, dấu hoa thị và các ký tự đặc biệt khác đều bị bỏ qua khi được đặt trong các dấu ngoặc đơn.

$ echo 'All sorts of things are ignored in single quotes, like $ & * ; |.' 

Nó sẽ cung cấp cho điều này:

All sorts of things are ignored in single quotes, like $ & * ; |.

Điều duy nhất không thể được đặt trong dấu ngoặc đơn là một trích dẫn.

Dấu ngoặc kép hoạt động tương tự như dấu ngoặc đơn, ngoại trừ dấu ngoặc kép vẫn cho phép trình bao hiểu các dấu đô la, dấu ngoặc kép ngược và dấu gạch chéo ngược. Người ta đã biết rằng dấu gạch chéo ngược ngăn không cho một ký tự đặc biệt nào được giải thích. Điều này có thể hữu ích trong dấu ngoặc kép nếu ký hiệu đô la cần được sử dụng làm văn bản thay vì cho một biến. Nó cũng cho phép các dấu ngoặc kép được thoát để chúng không được hiểu là phần cuối của chuỗi được trích dẫn.

$ echo "Here's how we can use single ' and double \" quotes within double quotes"

Nó sẽ cung cấp cho điều này:

Here's how we can use single ' and double " quotes within double quotes

Cũng có thể nhận thấy rằng dấu nháy đơn, nếu không sẽ được hiểu là phần đầu của chuỗi trích dẫn, bị bỏ qua trong dấu ngoặc kép. Các biến, tuy nhiên, được giải thích và thay thế bằng các giá trị của chúng trong dấu ngoặc kép.

$ echo "The current Oracle SID is $ORACLE_SID"

Nó sẽ cung cấp cho điều này:

The current Oracle SID is test

Báo giá lại hoàn toàn không giống như trích dẫn đơn hoặc đôi. Thay vì được sử dụng để ngăn chặn việc giải thích các ký tự đặc biệt, các trích dẫn ngược thực sự buộc thực thi các lệnh mà chúng kèm theo. Sau khi các lệnh kèm theo được thực thi, đầu ra của chúng được thay thế thay cho dấu ngoặc kép ở dòng ban đầu. Điều này sẽ rõ ràng hơn với một ví dụ.

$ today=`date '+%A, %B %d, %Y'`
$ echo $today 

Nó sẽ cung cấp cho điều này:

Monday, September 28, 2015 

3

Có một sự phân biệt rõ ràng giữa việc sử dụng ' '" ".

Khi ' 'được sử dụng xung quanh bất cứ thứ gì, không có "chuyển đổi hoặc dịch" được thực hiện. Nó được in như nó là.

Với " ", bất cứ thứ gì nó bao quanh, đều được "dịch hoặc biến đổi" thành giá trị của nó.

Bằng cách dịch / chuyển đổi tôi có nghĩa như sau: Bất kỳ điều gì trong dấu ngoặc đơn sẽ không được "dịch" thành giá trị của chúng. Họ sẽ được thực hiện như họ đang ở trong dấu ngoặc kép. Ví dụ : a=23, sau đó echo '$a'sẽ sản xuất $atrên đầu ra tiêu chuẩn. Trong khi đó echo "$a"sẽ sản xuất 23trên đầu ra tiêu chuẩn.


1
Bạn có ý nghĩa gì bởi "dịch" hoặc "chuyển đổi"?
Nico Haase

Câu trả lời này khá khó hiểu và nó không thêm bất cứ điều gì vào đầu các câu trả lời tốt hiện có.
codeforester

2
Đây là một câu trả lời ngắn gọn súc tích theo ý kiến ​​của tôi mà không quá dài dòng mà tôi dễ hiểu. Khi nói dịch / chuyển đổi, chúng có nghĩa là dấu ngoặc kép sẽ mở rộng biến trong đó dấu ngoặc đơn sẽ không mở rộng biến.
B_e_netty_

1
Vâng, đây là câu trả lời tốt nhất. Đây phải là câu trả lời được chấp nhận.
Jamey Kirby

3

Vì đây là câu trả lời thực tế khi xử lý dấu ngoặc kép trong bash , tôi sẽ thêm một điểm bị bỏ lỡ trong các câu trả lời ở trên, khi xử lý các toán tử số học trong trình bao.

Các bashvỏ hỗ trợ hai cách thực hiện hành động số học, một định nghĩa bởi được xây dựng trong letlệnh và các $((..))nhà điều hành. Cái trước đánh giá một biểu thức số học trong khi cái sau là một câu lệnh ghép.

Điều quan trọng là phải hiểu rằng biểu thức số học được sử dụng với việc lettrải qua quá trình chia tách từ, mở rộng tên đường dẫn giống như bất kỳ lệnh shell nào khác. Vì vậy, trích dẫn thích hợp và thoát cần phải được thực hiện.

Xem ví dụ này khi sử dụng let

let 'foo = 2 + 1'
echo $foo
3

Sử dụng dấu ngoặc đơn ở đây là hoàn toàn tốt ở đây, vì không cần mở rộng biến ở đây, hãy xem xét một trường hợp

bar=1
let 'foo = $bar + 1'

sẽ thất bại thảm hại, vì các $bartrích dẫn dưới đây sẽ không mở rộng và cần được trích dẫn hai lần như

let 'foo = '"$bar"' + 1'

Đây phải là một trong những lý do, $((..))nên luôn luôn được xem xét sử dụng let. Bởi vì bên trong nó, nội dung không chịu sự chia tách từ. Ví dụ trước sử dụng letcó thể được viết đơn giản là

(( bar=1, foo = bar + 1 ))

Luôn nhớ sử dụng $((..))mà không có dấu ngoặc đơn

Mặc dù $((..))có thể được sử dụng với dấu ngoặc kép, nhưng không có mục đích nào vì nó không thể chứa nội dung cần trích dẫn kép. Chỉ cần đảm bảo nó không được trích dẫn.

printf '%d\n' '$((1+1))'
-bash: printf: $((1+1)): invalid number
printf '%d\n' $((1+1))
2
printf '%d\n' "$((1+1))"
2

Có thể trong một số trường hợp đặc biệt sử dụng $((..))toán tử bên trong một chuỗi trích dẫn, bạn cần nội suy các trích dẫn theo cách mà toán tử hoặc không được trích dẫn hoặc dưới dấu ngoặc kép. Ví dụ, hãy xem xét một trường hợp, khi bạn buộc phải sử dụng toán tử bên trong một curlcâu lệnh để vượt qua bộ đếm mỗi khi yêu cầu được thực hiện, hãy làm

curl http://myurl.com --data-binary '{"requestCounter":'"$((reqcnt++))"'}'

Lưu ý việc sử dụng dấu ngoặc kép lồng nhau bên trong, mà không có chuỗi ký tự nào $((reqcnt++))được truyền vào requestCountertrường.


2
Charles Duffy là một trường hợp tốt ở đây để trích dẫn gấp đôi $((...)). Nó có thể là "một chút" hoang tưởng và khá khó có thể có IFS=0ví dụ, nhưng chắc chắn là không thể :)
PesaThe

Cũng có $[[...]]cú pháp kế thừa nhưng có lẽ bạn đã quên nó.
tripleee
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.