Tại sao tôi không thể cd đến một dấu ngã ('~')?


32

Viết kịch bản đầu tiên của tôi để tôi chắc chắn đây là một câu hỏi cơ bản, nhưng ai đó có thể vui lòng giải thích cho tôi tại sao tôi có thể:

cd ~
cd bin
cd ~/bin
cd 'bin'

Nhưng không

cd '~'
cd '~/bin'

Tôi cần đến cdmột đường dẫn thư mục có khoảng trắng ở một trong các tên thư mục, vì vậy tôi cần dấu ngoặc kép (đó là Windows Program Filesdưới rượu). Tôi có thể thực hiện xung quanh nó bằng hai cdlệnh, nhưng tại sao tôi không thể đặt ~dấu ngoặc kép?

Nếu tôi gõ cd '~'(hoặc cd "~") tôi nhận được:

bash: cd: ~: No such file or directory

29
Hãy tự hỏi mình điều này: nếu không làm việc theo cách đó, làm thế nào bạn cdvào một thư mục có tên ~?
Jörg W Mittag

2
Là một sidenote, nếu bạn đang viết một kịch bản, bạn nên sử dụng các đường dẫn tuyệt đối và tránh hoàn toàn cd. Sử dụng các biến để lưu trữ tên đường dẫn bạn không muốn gõ nhiều lần, ví dụ nhưpf=~/.wine/drive_c/Program\ Files/; cp /path/to/file "$pf"
món tráng miệng

8
@jamesqf: Tại sao một hệ thống hợp lý sẽ đoán rõ hơn tôi những gì tôi muốn đặt tên cho các tập tin và thư mục của mình? Ngoài ra, tôi không bao giờ hiểu tại sao Unix đi với tín hiệu ma thuật trong dải của các bộ tách thành phần đường dẫn và bộ kết thúc đường dẫn. Có gì sai với một tập tin / thư mục có tên /hoặc NUL?
Jörg W Mittag

3
@ JörgWMittag có lẽcd ./~
k_g

2
@jamesqf Chỉ cần lưu ý rằng trong lịch sử, các hệ thống tệp Unix cho phép bất kỳ char nào trong một tên tệp ngoại trừ '/' (dấu tách đường dẫn) và '\ 0' (NUL - char chấm dứt chuỗi) - như Jorg lưu ý. Không có hạn chế khác. Đã có nhiều triển khai hệ thống tập tin Unix, do đó, việc đưa ra các hạn chế trong bất kỳ một trong số chúng sẽ có khả năng tương thích bị phá vỡ và tăng độ phức tạp - và được xem là "kỳ lạ"! Và bản mở rộng '~' chỉ được giới thiệu tương đối gần đây trong csh và rộng rãi hơn trong bash, các tệp / thư mục có ký tự '~' không được biết đến (ví dụ: myfile ~ như một bản sao lưu cho myfile).
SusanW

Câu trả lời:


78

Như @karel đã lưu ý trong câu trả lời của mình, ~là một nhân vật đặc biệt và được Bash mở rộng vào thư mục nhà của người dùng hiện tại. Xem hướng dẫn của Bash về "Mở rộng Tilde" hoặc tìm kiếm tiêu đề "Mở rộng Tilde" trong trang man ( man bash).

Bất kỳ loại trích dẫn xung quanh việc ~ngăn chặn sự mở rộng dấu ngã này.


Để trả lời câu hỏi của bạn về cách bạn vẫn có thể sử dụng nó cdvào một thư mục có khoảng trắng trong tên của nó, có một vài lựa chọn thay thế:

  • Thay vào đó hãy bỏ qua dấu ngoặc kép và thoát khỏi khoảng trắng bằng dấu gạch chéo ngược:

    cd ~/foo/spaces\ are\ cool/bar
  • Trích dẫn phần còn lại của con đường, nhưng bỏ qua chúng xung quanh dấu ngã và dấu gạch chéo đầu tiên:

    cd ~/"foo/spaces are cool/bar"

    Như bạn thấy, bạn có thể nối các chuỗi được trích dẫn và không trích dẫn trong Bash bằng cách viết chúng cạnh nhau mà không có khoảng trắng ở giữa.

  • Sử dụng biến môi trường $HOMEthay vì dấu ngã, vẫn được mở rộng bên trong "dấu ngoặc kép" (nhưng không phải là "dấu ngoặc đơn"):

    cd "$HOME/foo/spaces are cool/bar"

3
@rexkogitans ~'/...'sẽ không hoạt động và không phải là câu trả lời này. ~/'...'hoặc ~/"..."sẽ làm việc
hvd

tld; dr: bởi vì đó là cú pháp shell
Sergiy Kolodyazhnyy

@hvd cảm ơn. Sửa lỗi chính tả. Đây là câu trả lời đầy đủ nhất và cũng giải thích cách giải quyết những gì OP muốn làm. ~/'path'là con đường để đi
rexkogitans

1
@hvd chỉ là một chút tò mò, tại sao nó không ~'/...'hoạt động? Dấu gạch chéo không phải là một ký tự đặc biệt nên có vẻ như nó sẽ hoạt động cả bên trong hoặc bên ngoài dấu ngoặc kép.
Kodos Johnson

6
@KodosJohnson Hãy xem phần của trang Bash về "Mở rộng Tilde". Đoạn có liên quan cũng được trích dẫn trong câu trả lời của món tráng miệng dưới đây. TL; DR: Quá trình mở rộng dấu ngã diễn ra nếu ký tự đầu tiên trong từ là dấu ngã không được trích dẫn, sau đó mọi thứ giữa dấu ngã đó và dấu gạch chéo không trích dẫn tiếp theo được coi là "tiền tố dấu ngã". Nếu tiền tố này không phải là một thứ hợp lệ như +, -, một số hoặc tên người dùng (trích dẫn trong đó cũng không được phép), việc mở rộng không thành công và bạn có ký tự ~.
Chỉ huy Byte

17

~ là một ký tự đặc biệt được trình diễn bởi shell là thư mục chính của người dùng đã đăng nhập. '~' được hiểu bởi shell là ký tự ~, không phải là thư mục chính của người dùng đã đăng nhập vì kèm theo một chuỗi bên trong hai ký tự trích dẫn duy nhất dẫn đến chuỗi đó được hiểu là một chuỗi văn bản bằng chữ.


~không phải là một bí danh theo nghĩa bashgiải nghĩa nó: Các bí danh cho phép một chuỗi được thay thế cho một từ khi nó được sử dụng như là từ đầu tiên của một lệnh đơn giản. . Như tôi giải thích trong câu trả lời của mình dưới đây, nó đúng hơn là một bản mở rộng.
tráng miệng

15

Đây là một bashtính năng được gọi là Tilde Expansion . Trích dẫn man bash:

Nếu một từ bắt đầu bằng ký tự dấu ngã không được trích dẫn (`~ '), tất cả các ký tự đứng trước dấu gạch chéo không được trích dẫn đầu tiên (hoặc tất cả các ký tự, nếu không có dấu gạch chéo không được trích dẫn) sẽ được coi là tiền tố dấu ngã. 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 dấu ngã được coi là tên đăng nhập có thể. Nếu tên đăng nhập này là chuỗi null, dấu ngã được thay thế bằng giá trị của tham số shell HOME. Nếu HOME không được đặt, thư mục chính của người dùng thực thi shell được thay thế.

Để mở rộng hoạt động, ký tự dấu ngã ~cần được bỏ qua, nếu không thì ký tự đó được lấy theo nghĩa đen và cdthất bại nếu không có thư mục có tên ~trong thư mục hiện tại. Xem câu trả lời hấp dẫn này để được giải thích về trích dẫn bash. Nếu bạn cần trích dẫn một phần của đường dẫn, do đó bạn có thể:

  1. trích dẫn ít nhất các ký tự cần trích dẫn với dấu ngoặc đơn, vd

    ~/dir' 'with' 'spaces/

    hoặc là

    ~/'dir with spaces/'
  2. trích dẫn ít nhất các ký tự cần trích dẫn với dấu ngoặc kép, ví dụ

    ~/dir" "with" "spaces/

    hoặc là

    ~/"dir with spaces/"
  3. chỉ trích dẫn các ký tự cần trích dẫn với dấu gạch chéo ngược, vd

    ~/dir\ with\ spaces/

Tilde Expansion có một số tính năng thú vị hơn, ví dụ:

  • ~+mở rộng đến giá trị của PWD, tức là thư mục làm việc hiện tại
  • ~-mở rộng đến giá trị của OLDPWD, tức là thư mục làm việc trước đó
  • ~john mở rộng đến thư mục chính được liên kết với tên đăng nhập

Ngẫu nhiên, cũng có thể 'vượt qua' với dấu gạch chéo ngược; ví dụ $ touch a; cd \a. (Tôi nghĩ rằng điều này có thể gặp rắc rối với cd \n, nhưng thử nghiệm ít nhất trên phiên bản của tôi bashcho thấy nó hoạt động tốt.)
LSpice

1

Khám phá bằng cách sử dụng echolệnh

Cách dễ nhất để khám phá cách mọi thứ hoạt động trong bash là với echolệnh. Trong trường hợp ~sử dụng này:

$ echo ~
/home/rick
$ echo '~'
~
$ echo "~"
~
$ echo `~`
bash: /home/rick: Is a directory

Như bạn có thể thấy, khi bạn trích dẫn đơn hoặc sử dụng dấu ngoặc kép xung quanh ~nó được hiểu theo nghĩa đen là một chuỗi và không được mở rộng dưới dạng một biến. Khi bạn sử dụng backticks (`), nó được thực thi như một lệnh và tạo ra một thông báo lỗi.

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.