Tại sao dấu ngã (~) không mở rộng bên trong dấu ngoặc kép?


54

Theo câu trả lời này và sự hiểu biết của riêng tôi, dấu ngã mở rộng đến thư mục chính:

$ echo ~
/home/braiam

Bây giờ, bất cứ khi nào tôi muốn mở rộng shell hoạt động, tức là sử dụng các tên biến như vậy $FOOvà không phá vỡ các ký tự không mong muốn, các khoảng trắng như vậy, v.v. người ta nên sử dụng dấu ngoặc kép ":

$ FOO="some string with spaces"
$ BAR="echo $FOO"
$ echo $BAR
echo some string with spaces

Tại sao bản mở rộng này không hoạt động với dấu ngã?

$ echo ~/some/path
/home/braiam/some/path
$ echo "~/some/path"
~/some/path


3
Cũng lưu ý rằng điều này có sự không nhất quán khi cung cấp một đối số chương trình trên dòng lệnh mà đối số lệnh --path ~/myfilemở rộng nhưng --path=~/myfilekhông.
Ángel



Một biến thể về chủ đề này là unix.stackexchange.com/questions/279565 .
JdeBP

Câu trả lời:


45

Lý do, bởi vì bên trong dấu ngoặc kép, dấu ngã ~không có ý nghĩa đặc biệt, nó được coi là nghĩa đen.

POSIX định nghĩa Báo giá kép là:

Các ký tự được đặt trong dấu ngoặc kép ("") sẽ giữ nguyên giá trị bằng chữ của tất cả các ký tự trong dấu ngoặc kép, ngoại trừ ký tự đô la ký tự, backquote và dấu gạch chéo ngược,

...

Ứng dụng phải đảm bảo rằng trích dẫn kép được đặt trước dấu gạch chéo ngược được bao gồm trong dấu ngoặc kép. Tham số '@' có ý nghĩa đặc biệt trong dấu ngoặc kép

Trừ $, `, \@, các nhân vật khác được coi là dấu ngoặc kép bên trong chữ.


9
Trong trường hợp tôi đoán bạn nên sử dụng $HOME.
Seth

11
Hoặc bạn chỉ có thể không trích dẫn ~, ví dụls -l ~/"My Documents"
Andrew Medico

Điều này rất không trực quan. Lý do họ chọn để làm điều này là gì? (Câu trả lời này không thực sự đưa ra lý do, mà chỉ đưa ra tiêu chuẩn, nhưng có lẽ tiêu chuẩn được viết theo cách đó vì một lý do .)
iconoclast

1
@iconoclast nếu bạn thực sự muốn một "lý do tại sao họ thực hiện theo cách này" thay vào đó hãy đọc câu trả lời của Stephane .
Braiam

2
Vì vậy, @iconoclast, tại sao bầu trời màu xanh? :) :) :)
Jesse Chisholm

32

Mở rộng Tilde được định nghĩa bởi POSIX là:

Một "tiền tố tilde" bao gồm một ký tự <tilde> không được trích dẫn ở đầu từ, theo sau là tất cả các ký tự đứng trước dấu gạch chéo <slash> đầu tiên trong từ hoặc tất cả các ký tự trong từ nếu không có < dấu gạch chéo>. Trong một bài tập, nhiều tiền tố dấu ngã có thể được sử dụng: [...] theo sau <dấu bằng> của bài tập, theo bất kỳ <dấu> nào không được trích dẫn hoặc cả hai. [...] Nếu không có ký tự nào trong tiền tố dấu ngã được trích dẫn, thì các ký tự trong tiền tố dấu ngã sau <tilde> được coi là tên đăng nhập có thể có từ cơ sở dữ liệu người dùng. [...] Nếu tên đăng nhập là null (có nghĩa là tiền tố dấu ngã chỉ chứa dấu ngã), tiền tố dấu ngã được thay thế bằng giá trị của biến HOME. Nếu HOME không được đặt, kết quả không được chỉ định. [...]

Vì vậy, câu trả lời ngắn nhất là "bởi vì nó được định nghĩa theo cách đó": trích dẫn bất kỳ ký tự nào trong tiền tố, bao gồm cả ~, ngăn chặn sự mở rộng.

Nó cũng định nghĩa việc mở rộng là luôn luôn dẫn đến một từ duy nhất, vì vậy trích dẫn sẽ không cần thiết:

Tên đường dẫn do mở rộng dấu ngã sẽ được xử lý như thể được trích dẫn để ngăn chặn nó bị thay đổi bằng cách tách trường và mở rộng tên đường dẫn.

Trong trường hợp một số đường dẫn yêu cầu trích dẫn, nhưng phần còn lại là tiền tố dấu ngã, bạn có thể kết hợp mở rộng dấu ngã và trích dẫn thông thường một cách đơn giản:

$ cat ~/"file name with spaces"

Trên "tại sao" rộng hơn: vì không có cách sử dụng có thể hiểu được để phân tách từ ~, đó phải là hành vi mặc định, thay vì yêu cầu trích dẫn. Bởi vì không cần phải trích dẫn nó, việc đưa ra ~một ý nghĩa đặc biệt trong các trích dẫn sẽ là một sự phức tạp không cần thiết. Và, tất nhiên, lý do lịch sử có nghĩa là nó không thể thay đổi ngay cả khi điều đó là mong muốn.


Theo hướng dẫn bash này , việc mở rộng dấu ngã xảy ra trước khi tách khoảng trắng. Có cách nào để mở rộng dấu ngã một cách an toàn, ngay cả khi thư mục chính của bạn có khoảng trắng trong đó không? Thông thường, tất nhiên, bạn sẽ làm điều này với "".
Lucretiel

Việc mở rộng là một từ duy nhất; xem đoạn trích dẫn thứ hai trong câu trả lời.
Michael Homer

23

~ bắt nguồn từ vỏ C, rất lâu trước khi nó được thêm vào vỏ Korn và sau đó được thêm vào đặc tả vỏ POSIX.

Trong C-shell, ~là một toán tử toàn cầu (được mở rộng theo cùng một thói quen như mở rộng *.txtchẳng hạn), do đó, phần còn lại của quá trình tạo khối không được thực hiện trong dấu ngoặc kép.


11

Mặc dù điều này không trả lời tại sao nó được thiết kế theo cách đó, nhưng bạn sử dụng $HOMEthay thế nếu bạn cần thay thế, vì về cơ bản đó là những gì ~.

$ echo "$HOME/some/path"
/home/braiam/some/path

6
điều này không hiệu quả với~otheruser
Johannes Kuhn

2
Đúng, nhưng bạn có thể làm: THEM = ~ người dùng khác sau đó sử dụng "$ THEM / some / path"
kết hợp

1
Cách giải quyết cho ~otheruserthấy một ý tưởng tồi là gì khi đối xử ~khác với các biến và những thứ khác được mở rộng bên trong dấu ngoặc kép.
iconoclast
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.