Tại sao ls -d cũng liệt kê các tập tin, và nó được ghi lại ở đâu?


48
  • khi chỉ định ls --directory a*nó chỉ liệt kê các thư mục bắt đầu bằnga*
  • NHƯNG nó liệt kê các tập tin VÀ thư mục bắt đầu bằng a

Câu hỏi :

  • Tôi có thể tìm thấy một số tài liệu về điều này ở đâu, ngoài maninfonơi mà tôi nghĩ rằng tôi đã xem xét kỹ lưỡng?
  • cái này chỉ hoạt động trong BASH?


5
echo a*cũng sẽ liệt kê cho bạn các tập tin bắt đầu bằng a(nếu có). Chỉ để làm rõ hơn rằng nó không lslàm điều này mà là bash.
tro 108

Câu trả lời:


89

Các a**a*cú pháp được thực hiện bởi vỏ, không phải do lslệnh.

Khi bạn gõ

ls a*

tại dấu nhắc shell của bạn, shell sẽ mở rộng a*thành một danh sách tất cả các tệp trong thư mục hiện tại có tên bắt đầu bằng a. Ví dụ, nó có thể mở rộng a*thành chuỗi a1 a2 a3và chuyển chúng thành đối số ls. Bản lsthân lệnh không bao giờ nhìn thấy *nhân vật; nó chỉ nhìn thấy ba đối số a1, a2a3.

Đối với mục đích mở rộng ký tự đại diện, "tệp" đề cập đến tất cả các thực thể trong thư mục hiện tại. Ví dụ: a1có thể là một tệp bình thường, a2có thể là một thư mục và a3có thể là một liên kết tượng trưng. Tất cả chúng đều có các mục nhập thư mục và việc mở rộng ký tự đại diện của shell không quan tâm loại thực thể mà các mục đó đề cập đến.

Thực tế tất cả các shell bạn có khả năng chạy ngang qua (bash, sh, ksh, zsh, csh, tcsh, ...) thực hiện các ký tự đại diện. Các chi tiết có thể khác nhau, nhưng cú pháp cơ bản của việc *ghép 0 hoặc nhiều ký tự và ?khớp với bất kỳ ký tự đơn nào là phù hợp một cách hợp lý.

Đối với bash nói riêng, điều này được ghi lại trong phần "Mở rộng tên tệp" trong hướng dẫn sử dụng bash; chạy info bashvà tìm kiếm "Mở rộng tên tệp", hoặc xem tại đây .

Thực tế là điều này được thực hiện bởi shell chứ không phải bởi các lệnh riêng lẻ, có một số hậu quả thú vị (và đôi khi đáng ngạc nhiên). Điều tốt nhất về nó là việc xử lý ký tự đại diện phù hợp với (rất gần) tất cả các lệnh; nếu shell không làm điều này, chắc chắn một số lệnh sẽ không làm phiền và những lệnh khác sẽ làm điều đó theo những cách khác nhau mà tác giả nghĩ là "tốt hơn". (Tôi nghĩ shell lệnh Windows có vấn đề này, nhưng tôi không đủ quen thuộc với nó để bình luận thêm.)

Mặt khác, thật khó để viết một lệnh để đổi tên nhiều tệp. Nếu bạn viết:

mv *.log *.log.bak

nó có thể sẽ thất bại, vì *.log.bakđược mở rộng dựa trên các tệp đã tồn tại trong thư mục hiện tại. Có những lệnh thực hiện loại điều này, nhưng chúng phải sử dụng cú pháp của riêng chúng để xác định cách các tệp được đổi tên. Một số lệnh (chẳng hạn như find) có thể thực hiện mở rộng ký tự đại diện của riêng chúng; bạn phải trích dẫn các đối số để ngăn chặn sự mở rộng của shell:

find . -name '*.txt' -print

Mở rộng ký tự đại diện của shell hoàn toàn dựa trên cú pháp của đối số dòng lệnh và tập hợp các tệp hiện có. Nó không thể bị ảnh hưởng bởi ý nghĩa của lệnh. Ví dụ: nếu bạn muốn di chuyển tất cả .logcác tệp lên thư mục mẹ, bạn có thể nhập:

mv *.log ..

Nếu bạn quên ..:

mv *.log

và có hai .logtệp trong thư mục hiện tại, nó sẽ mở rộng thành:

mv one.log two.log

Nó sẽ đổi tên one.logvà clobber two.log.

EDIT : Và sau 52 lần nâng cấp, chấp nhận và huy hiệu Guru, có lẽ tôi thực sự nên trả lời câu hỏi trong tiêu đề.

Các -dhoặc --directorytùy chọn để lskhông nói với nó để chỉ liệt kê các thư mục. Nó bảo nó liệt kê các thư mục giống như chính chúng, không phải nội dung của chúng. Nếu bạn đặt tên thư mục làm đối số ls, theo mặc định, nó sẽ liệt kê nội dung của thư mục, vì đó thường là những gì bạn quan tâm. -dTùy chọn này chỉ liệt kê danh sách thư mục đó. Điều này có thể đặc biệt hữu ích khi kết hợp với ký tự đại diện. Nếu bạn gõ:

ls -l a*

lssẽ cung cấp cho bạn một danh sách dài của mỗi tệp có tên bắt đầu anội dung của mỗi thư mục có tên bắt đầu a. Nếu bạn chỉ muốn một danh sách các tệp và thư mục, mỗi dòng cho một dòng, bạn có thể sử dụng:

ls -ld a*

tương đương với:

ls -l -d a*

Hãy nhớ lại rằng lslệnh không bao giờ nhìn thấy *nhân vật.

Về phần tài liệu này, man lssẽ hiển thị cho bạn tài liệu về lslệnh trên bất kỳ hệ thống nào giống Unix. Trên hầu hết các hệ thống dựa trên Linux, lslệnh là một phần của gói GNU coreutils; nếu bạn có infolệnh, info lshoặc info coreutils lssẽ cung cấp cho bạn tài liệu chính xác và toàn diện hơn. Các hệ thống khác, chẳng hạn như MacOS, có thể sử dụng các phiên bản khác nhau của lslệnh và có thể không có infolệnh; Đối với những hệ thống, sử dụng man ls. Và ls --helpsẽ hiển thị một thông báo sử dụng tương đối ngắn (117 dòng trên hệ thống của tôi) nếu bạn đang sử dụng triển khai GNU coreutils.

Và có, ngay cả các chuyên gia cần phải tham khảo tài liệu bây giờ và sau đó. Xem thêm trò đùa kinh điển này .


8
@Thomas: a*mở rộng ra danh sách tất cả các tệp trong thư mục hiện tại có tên bắt đầu bằng a.
Keith Thompson

2
@Thomas: Hoặc trong bất kỳ thư mục nào bạn chỉ định:ls subdir/a*
Keith Thompson

1
Để thực sự thấy lệnh được thực thi sau khi mở rộng shell, echonó. Vì vậy, nếu bạn muốn biết những gì đang xảy ra khi bạn làm ls a*, trước tiên hãy thực hiệnecho ls a*
Carlos Campderrós

1
hoặc chỉ echo a*... vỏ dù mở rộng toàn cầu
Vô dụng

2
@sendmoreinfo: Điều đó phụ thuộc vào trình bao và cài đặt. Trong csh và tcsh, việc mở rộng toàn cầu không thành công là một lỗi. Trong bash, shopt -s failglobgây ra hành vi tương tự. Cài đặt nullglobnhưng không failglobgây ra, ví dụ, *nosuchfile*để mở rộng thành một chuỗi trống.
Keith Thompson

27

Xem câu trả lời của Keith Thompson; nhưng để giải thích tại sao ls --directory a*hiển thị tệp thư mục: --directoryTùy chọn không chặn các tệp không phải thư mục. Thay vào đó, nó liệt kê các thư mục như vậy, trong khi nó sẽ liệt kê nội dung của chúng. Thí dụ:

$ mkdir foo
$ touch foo/bar
$ ls foo
bar
$ ls --directory foo
foo

3
ví dụ đó hấp dẫn hơn với -Ftùy chọn
glenn jackman

6

Để được rõ ràng, nó được ghi lại trong trang hướng dẫn ls (1) :

-d, --directory liệt kê các mục trong thư mục thay vì nội dung và không liên kết tượng trưng

để công bằng, "các mục thay vì nội dung" có thể giải thích rõ hơn:

Nếu FILE là một thư mục, hãy hiển thị mục nhập thư mục thay vì liệt kê nội dung của thư mục đó. Nếu FILE là một liên kết tượng trưng, ​​hãy hiển thị chính mục nhập liên kết thay vì tệp được liên kết bởi liên kết.


Để được mô tả, trong khi tùy chọn -d có thể được giải thích (nếu căng thẳng) trong trang man, mở rộng đối số và ký tự đại diện không được ghi lại trong trang ls man vì nó được thực hiện bởi trình bao. Nếu bạn tắt mở rộng tên tệp trong trình bao của mình, "ls a *" sẽ chỉ hiển thị cho bạn một tệp có tên theo nghĩa đen là 'a *'.
Johnny

Để được mô phạm, trong khi mở rộng vỏ được trả lời bởi những người trả lời khác, không ai trong số họ giải quyết lời giải thích ít ỏi và làm thế nào nó có thể bị đọc sai. Nếu bạn muốn tôi nhắc lại điều đã được nói rõ, xin hãy thẳng thắn hơn.
msw

4

Globbing

Như đã được giải thích, việc mở rộng *(và mở rộng tương tự) được gọi là globbing trong biệt ngữ Unix và thường là một tính năng của bộ xử lý lệnh (được gọi là "shell" theo cách nói của Unix). Vì vậy, Globing có thể được sử dụng ở nhiều nơi khác nữa; gõ man 7 globvào vỏ của bản phân phối Linux cổ điển (hoặc xem phần này ) để biết thêm về globbing.

Trong thời kỳ đầu Unix, globthực tế đã được thực hiện bởi một chương trình riêng biệt có tên /etc/glob(xem trang 10 của tài liệu hướng dẫn UNIX cũ này để biết tài liệu cho việc đó). Ngày nay, nó là một thói quen mã được cung cấp bởi các thư viện mã và thường được sử dụng bởi các shell. Nguồn : Wikipedia .

Thư mục

Về lý do tại sao ls -dliệt kê các tập tin cũng như các thư mục ...

Các lstrang người đàn ông giải thích lý do tại sao điều này xảy ra, nhưng với một lời giải thích rất ngắn gọn. Vì vậy, đây là một nỗ lực tại một giải thích mở rộng:

Theo mặc định, lsliệt kê nội dung của các thư mục khi được đặt tên của chúng và sẽ làm điều tương tự cho các liên kết tượng trưng đến các thư mục. Các -dphương tiện lựa chọn, "khi được đặt tên (s) của thư mục (ies)" (mà cũng có thể được ngầm bởi globbing) , chỉ hiển thị các _name_s của thư mục (ies), nhưng không nội dung của họ. Tương tự, khi được cung cấp (rõ ràng hoặc ngầm ) tên của các liên kết tượng trưng cho các thư mục , hãy hiển thị tên tệp của liên kết tượng trưng, ​​không phải nội dung của thư mục mà nó tham chiếu.

Các -dtùy chọn có gì để làm, như xa như tôi có thể nói, với mục được liệt kê; điều này có thể được thực hiện (nguồn: ở đây ) với find, như vậy : find . -maxdepth 1 -type d. Tôi không chắc chắn nếu có một cách tốt để làm như vậy chỉ với GNU ls. Dưới đây là một số ví dụ về cách sử dụng findlệnh.

Vì vậy, để tổng hợp: Theo mặc định lshiển thị nội dung của các thư mục khi được đặt tên đường dẫn của họ. -dthay đổi hành vi này, chỉ hiển thị tên thư mục, như sẽ được thực hiện cho một tệp tiêu chuẩn.


3

Tài liệu không nói rằng nó chỉ liệt kê các mục nhập thư mục thay vì khi lsnhận được tên thư mục, nó liệt kê mục nhập dir thay vì nội dung của nó. Cách tốt nhất để hiểu là bằng ví dụ:

> {ice} ~ :10:47 % ls -l / 
total 97
drwxr-xr-x   2 root root  4096 May  3 00:27 bin
drwxr-xr-x   4 root root  1024 May  3 14:17 boot
drwxr-xr-x   2 root root  4096 Apr 29 13:44 cdrom
drwxr-xr-x  18 root root  4420 May  9 09:58 dev
...
lrwxrwxrwx   1 root root    33 May  3 14:16 vmlinuz -> boot/vmlinuz-3.9.0-030900-generic
lrwxrwxrwx   1 root root    29 May  3 11:07 vmlinuz.old -> boot/vmlinuz-3.8.0-19-generic
> {ice} ~ :10:47 % ls -ld /
drwxr-xr-x 25 root root 4096 May  3 14:16 /

2

Các tài liệu là một phần của vỏ . Cụ thể, shell thực hiện các mở rộng và thay thế khác nhau theo một thứ tự cụ thể trước khi thực hiện một lệnh.

Trình tự mở rộng từ cho trình bao tương thích Bourne

  1. Mở rộng Tilde
  2. Mở rộng tham số
  3. Bộ chỉ huy thay thế
  4. Mở rộng số học
  5. Tách trường
  6. Mở rộng tên đường dẫn
  7. Trích dẫn loại bỏ

Vì vậy, lslệnh thậm chí không nhìn thấy các *ký tự, các đối số đã được mở rộng với tất cả các tệp khớp với a*mẫu hình cầu. Điều này không giống như trên Windows, nơi mỗi lệnh cần tên tệp globalbing phải tự thực hiện tính năng này.


1

Từ khóa bạn cần ( man bash) là "Mở rộng tên đường dẫn".


3
giống như "Mở rộng tên đường dẫn" hoặc "Tạo tên tệp". Liên quan đến "khớp mẫu", nhưng không giống nhau.
Stéphane Chazelas

@StephaneChazelas Thật vậy, nhưng "khớp mẫu" là phần phụ của "mở rộng tên đường dẫn" trong trang man trong khi "Tạo tên tệp" hoàn toàn không xảy ra ở đó (chỉ trong tài liệu thông tin).
Hauke ​​Laging
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.