~ (Dấu ngã) khi được sử dụng làm tiền tố cho đường dẫn là gì?


11

Chỉnh sửa: Đây là bản sao của /programming/998626/meaning-of-tilde-in-linux-bash-not-home-directory/ . Tôi không có tiếng là đóng câu hỏi này thành bản sao.

Tôi không đề cập đến ~như trong thư mục nhà mà là thế này:

$ ls ~foo/bar
/some/mount/point/foo/bar

Tuy nhiên, nếu tôi thử nó với một điểm gắn kết khác, ví dụ:

$ mount | ag "/dev "
devfs on /dev (devfs, local, nobrowse)
$ ls /dev/stdin
/dev/stdin
$ ls ~stdin
zsh: no such user or named directory: stdin . 
# bash has a similar error message: 
ls: ~stdin: No such file or directory

Cái ~gọi là gì trong bối cảnh này? Làm thế nào nó hoạt động?

Chỉnh sửa: Thêm thông tin dựa trên một số ý kiến ​​dưới đây:

  1. Tôi có thể chứng thực rằng đó fookhông phải là tên người dùng trên hệ thống của tôi.
  2. Khi cố gắng tự động hoàn ls -lah ~tất, không phải tất cả các tùy chọn đều được hiển thị. tức là tôi có thể cd ~qux, khi quxkhông hiển thị trong tự động hoàn thành. Một lần nữa quxkhông phải là người dùng trong hệ thống của tôi.
  3. Nếu nó quan trọng /some/mount/pointlà một chia sẻ mạng.
  4. Tất cả các chi tiết đề xuất một số muckery đường dẫn được đặt tên, tính năng vỏ Z của mở rộng tên đường dẫn, nhưng điều này cũng hoạt động trong bash, dường như không hỗ trợ những thứ như đường dẫn được đặt tên của vỏ Z.

5
~foolà thư mục nhà của người dùng foo. Nếu người dùng không được chỉ định, người dùng hiện tại là mặc định.
DopeGhoti

Nhưng trong trường hợp này, /some/mount/pointchắc chắn không phải là thư mục nhà của tôi. cd ~đưa tôi đến /Users/$username/- trận đấu nào$HOME
RD

1
zshdường như cũng sử dụng dấu ngã để chỉ ra các thư mục được đặt tên.
DopeGhoti

Tôi cũng nghi ngờ điều đó !! Ngoại trừ một số lý do, một loạt các lệnh tôi đã đăng ở trên cũng hoạt động trong bash ( bash -c "ls ~foo/bar") - không có tên thư mục. Hơn nữa, ngay cả trong zsh, nếu tôi kiểm tra env, tôi không thấy bất kỳ thư mục được đặt tên nào được thiết lập. Tôi đang dùng Mac OS và tôi cảm thấy đây là một số tính năng dành riêng cho OS X.
RD

1
Bạn chỉ nói ~foo. Lấy chuỗi thực tế (không phải ví dụ foo) và làm grep "actual username" /etc/passwd. ~textchỉ nên hoạt động cho tên người dùng đăng nhập có thể theo hướng dẫn sử dụng bash (không nhất thiết có nghĩa là nó thực sự có thể đăng nhập; trong trường hợp người dùng hệ thống, chẳng hạn như ~lp). Trong tất cả các thử nghiệm của tôi, ~stringtương ứng với stringtên người dùng.
Sergiy Kolodyazhnyy

Câu trả lời:


14

~ Foo là gì

Trích dẫn từ hướng dẫn bash (có thêm nhấn mạnh):

Nếu một từ bắt đầu bằng ký tự dấu ngã không được trích dẫn (`~ '), thì 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ố tilde được trích dẫn, 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ể .

~foo mở rộng đến foothư mục chính của người dùng chính xác như được chỉ định trong /etc/passwd. Lưu ý rằng điều này có thể bao gồm tên người dùng hệ thống; điều đó không nhất thiết có nghĩa là người dùng hoặc họ thực sự có thể đăng nhập cục bộ (ví dụ họ có thể đăng nhập thông qua các khóa SSH).

Trong thực tế, như đã lưu ý trong các ý kiến , bashsẽ sử dụng getpwnamchức năng. Đó là chức năng riêng của mình được quy định bởi POSIX tiêu chuẩn, do đó nên tồn tại trên hầu hết các giống Unix hệ thống, bao gồm cả hệ điều hành MacOS X . Chức năng này không giới hạn /etc/passwdchỉ và tìm kiếm các cơ sở dữ liệu khác, chẳng hạn như LDAP và NIS. Đoạn trích cụ thể từ bash mã nguồn , tilde.ctập tin, bắt đầu từ dòng 394:

  /* No preexpansion hook, or the preexpansion hook failed.  Look in the
     password database. */
  dirname = (char *)NULL;
#if defined (HAVE_GETPWNAM)
  user_entry = getpwnam (username);
#else
  user_entry = 0;

Ví dụ thực tế

Dưới đây bạn có thể xem các bài kiểm tra với tên người dùng hệ thống trên hệ thống của tôi. Chú ý đến passwdmục tương ứng và kết quả củals ~username

$ grep '_apt' /etc/passwd
_apt:x:104:65534::/nonexistent:/bin/false
$ ls ~_apt
ls: cannot access '/nonexistent': No such file or directory
$ grep '^lp' /etc/passwd
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
$ ls ~lp
ls: cannot access '/var/spool/lpd': No such file or directory

Ngay cả khi _apttài khoản chẳng hạn bị khóa như được đề xuất bởi đầu ra của passwd -S aptnó, nó vẫn hiển thị như tên đăng nhập có thể:

_apt L 11/29/2017 0 99999 7 -1

Xin lưu ý: Đây không phải là tính năng dành riêng cho macOS, mà là tính năng dành riêng cho hệ vỏ.


Tôi nghi ngờ trình bao có thể dựa vào việc tìm hiểu bất cứ điều gì về ngày hết hạn tài khoản hoặc nếu nó bị khóa hoặc bất cứ điều gì khi mở rộng dấu ngã. Ví dụ: trên Linux, ngày hết hạn được lưu trữ /etc/shadowcùng với thông tin xác thực được bảo vệ khác, như mật khẩu. Tham chiếu trong passwdchỉ là về việc làm cho mật khẩu không hợp lệ: điều đó sẽ không ngăn chặn xác thực thông qua các phương tiện khác.
ilkkachu

@ilkkachu Đúng, bạn nói đúng. Tôi đã kiểm tra rằng với việc thêm testuservà sửa đổi ngày hết hạn mật khẩu. Tên người dùng vẫn xuất hiện trong hoàn thành tab. Tôi đã xóa câu trả lời đó khỏi câu trả lời
Sergiy Kolodyazhnyy

1
Vấn đề duy nhất với câu trả lời này là nó trích dẫn bashtrang người đàn ông (và có vẻ như cũ). OP thực sự đang sử dụng zsh(có thể rõ ràng hơn), mặc dù trong các bình luận, nó được đề cập bashcó hành vi tương tự.
Ken Wayne VanderLinde

2
Bạn có thể sử dụng getent passwd foothay vì grep foo /etc/passwordtuân theo các cơ chế tra cứu tương tự như trình bao - có lẽ bao gồm các dịch vụ thư mục dựa trên mạng mà @Abigail đề cập.
RJHunter

1
Được chấp nhận là câu trả lời cho bit 'chẳng hạn như bit LDAP và NIS', kết quả là chính xác trong trường hợp của tôi!
RD

5

Tóm lại lý do tại sao bạn nhìn thấy một cái gì đó ~foo/bar, đó là bởi vì bạn có một người dùng có tên footrên hệ thống với một thư mục có tên bartrong thư mục chính của họ.

Xem giải pháp này trong một cộng đồng khác giải thích tại sao (dấu ngã) ~không chỉ là "thư mục chính".

Nếu bạn có một người dùng có tên bintrên hệ thống của mình, thì bạn có thể liệt kê nội dung của thư mục chính của bin theo lệnh:

ls ~bin

Một điều khác bạn có thể thử là sử dụng hoàn thành tab sau khi gõ dấu nhắc sau (không trả lại vận chuyển, chỉ sử dụng phím tab):

ls -lah ~ tab

để xem danh sách các thư mục chính của người dùng ~sẽ mở rộng nếu bạn tiếp tục. Ví dụ (cắt ngắn) đầu ra của việc hoàn thành tabls -lah ~ tab

$ ls -lah ~ [tab]
~antman/            ~games/
~bin/               ~mail/

1
+1 để hoàn thành tab. Điều này cho thấy rõ ràng tất cả các tên người dùng mà bash có thể nhận được tên đăng nhập có thể có từ đó /etc/passwd. Nó ngay lập tức giúp làm rõ những gì đang xảy ra nếu người dùng tất nhiên biết về tên người dùng họ có trên hệ thống.
Sergiy Kolodyazhnyy

2
Cảm ơn mẹo về việc hoàn thành bash - dẫn đến một số kết quả tự động hoàn thành thú vị. Mặc dù ~foođã tự động hoàn tất, tôi có thể chứng thực rằng đó fookhông phải là người dùng trên hệ thống của tôi (và thực sự không tồn tại /etc/passwd). Hơn nữa, tất cả các thư mục / tệp /some/mount/pointhiển thị trong tự động hoàn thành là siêu thú vị.
RD
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.