Kết quả của ls *, ls ** và ls ***


86

Tôi biết sử dụng lệnh lssẽ liệt kê tất cả các thư mục. Nhưng ls *lệnh làm gì? Tôi đã sử dụng nó và nó chỉ liệt kê các thư mục. Là ngôi sao ở phía trước lscó nghĩa là nó có thể liệt kê các thư mục sâu đến mức nào?

Câu trả lời:


155

lsliệt kê các tệp và nội dung của các thư mục mà nó đang được truyền dưới dạng đối số và nếu không có đối số nào được đưa ra, nó sẽ liệt kê thư mục hiện tại. Nó cũng có thể được thông qua một số tùy chọn ảnh hưởng đến hành vi của nó (xem man lsđể biết chi tiết).

Nếu lsđang được thông qua một đối số được gọi *, nó sẽ tìm một tệp hoặc thư mục được gọi *trong thư mục hiện tại và liệt kê nó giống như bất kỳ đối số nào khác. lskhông đối xử với *nhân vật theo bất kỳ cách nào khác hơn bất kỳ ai khác.

Tuy nhiên, nếu ls *là một dòng lệnh shell , thì shell sẽ mở rộng *theo quy tắc Globing của shell tương ứng (còn được gọi là quy tắc Tạo tên tệp hoặc Mở rộng tên tệp ).

Trong khi các shell khác nhau hỗ trợ các toán tử toàn cầu khác nhau, hầu hết chúng đều đồng ý về cách đơn giản nhất *. *như một mô hình có nghĩa là bất kỳ số lượng nhân vật, vì vậy *như một globsẽ mở rộng danh sách các tập tin trong thư mục hiện hành phù hợp với mô hình đó. Tuy nhiên, có một ngoại lệ là một .ký tự dấu chấm ( ) hàng đầu trong tên tệp phải được khớp một cách rõ ràng, do đó *thực sự mở rộng ra danh sách các tệp và thư mục không bắt đầu bằng .(theo thứ tự từ điển).

Ví dụ, nếu thư mục hiện hành chứa các tập tin gọi là ., .., .foo, -lfoo bar, *sẽ được mở rộng bằng vỏ để hai đối số để truyền đến ls: -lfoo bar, vì vậy nó sẽ như thể bạn đã gõ:

ls -l "foo bar"

hoặc là

'ls' "-l" foo\ bar

Đó là ba cách để chạy chính xác cùng một lệnh. Trong cả 3 trường hợp, lslệnh (có thể sẽ được thực thi từ /bin/lstra cứu các thư mục được đề cập trong $PATH) sẽ được thông qua 3 đối số đó: "ls", "-l" và "foo bar".

Ngẫu nhiên, trong trường hợp này, lssẽ coi cái đầu tiên (nói đúng thứ hai ) là một lựa chọn.

Bây giờ, như tôi đã nói, các shell khác nhau có các toán tử toàn cầu khác nhau. Một vài thập kỷ trước, đã zshgiới thiệu **/toán tử - có nghĩa là phù hợp với bất kỳ cấp độ thư mục con nào, viết tắt (*/)#***/tương tự ngoại trừ việc nó tuân theo các liên kết tượng trưng trong khi giảm dần các thư mục.

Một vài năm trước (tháng 7 năm 2003, ksh93o+), ksh93đã quyết định sao chép hành vi đó nhưng quyết định biến nó thành tùy chọn và chỉ bao gồm **trường hợp (không ***). Ngoài ra, trong khi **một mình không đặc biệt zsh(chỉ có nghĩa giống *như trong các shell truyền thống khác vì **có nghĩa là bất kỳ số lượng ký tự nào được theo sau bởi bất kỳ số lượng ký tự nào), trong ksh93, **có nghĩa giống như **/*(vì vậy bất kỳ tệp hoặc thư mục nào bên dưới tệp hiện tại (không bao gồm các tập tin ẩn).

bashsao chép ksh93một vài năm sau đó (tháng năm 2009, bash 4.0), với cú pháp tương tự, nhưng một sự khác biệt đáng tiếc: của bash **giống như zsh's ***, đó là nó được sau liên kết tượng trưng khi recursing vào thư mục con mà nói chung là không phải những gì bạn muốn nó làm và có thể có tác dụng phụ khó chịu. Nó đã được sửa một phần trong bash-4.3 trong đó các liên kết tượng trưng vẫn được theo dõi, nhưng đệ quy dừng lại ở đó. Nó đã được sửa hoàn toàn trong 5.0.

yashđược thêm vào **trong phiên bản 2.0 năm 2008, được bật với extended-globtùy chọn. Thực hiện của nó là gần gũi hơn với zsh's ở chỗ **không thôi là không đặc biệt. Trong phiên bản 2.15 (2009), nó đã thêm vào ***như trong zshvà hai phần mở rộng của chính nó: .**.***bao gồm các thư mục ẩn khi đệ quy (trong zsh, D vòng loại toàn cầu (như trong **/*(D)) sẽ xem xét các tệp và thư mục ẩn, nhưng nếu bạn chỉ muốn duyệt qua thư mục nhưng không mở rộng các tập tin ẩn, bạn cần ((*|.*)/)#*hoặc **/[^.]*(D)).

Các vỏ cá cũng hỗ trợ **. Giống như phiên bản trước đó bash, nó tuân theo các liên kết tượng trưng khi hạ xuống cây thư mục. Trong vỏ đó tuy nhiên **/*không giống như **. **là một phần mở rộng *có thể mở rộng một số thư mục. Trong fish, **/*.csẽ phù hợp a/b/c.cnhưng không a.c, trong khi a**.csẽ phù hợp a.cab/c/d.czsh's **/.*ví dụ đã được viết .* **/.*. Ở đó, ***được hiểu như **sau bởi *vì vậy giống như **.

tcshcũng đã thêm một globstartùy chọn trong V6.17.01 (tháng 5 năm 2010) và hỗ trợ cả hai *****à la zsh.

Vì vậy, trong tcsh, bashksh93, (khi tùy chọn tương ứng được kích hoạt ( globstar)) hoặc fish, **mở rộng tất cả các file và thư mục dưới một hiện nay, và ***cũng giống như **cho fish, một liên kết tượng trưng đi qua **cho tcshglobstar, và giống như *trong bashksh93(mặc dù nó không phải là không thể, các phiên bản tương lai của các shell đó cũng sẽ đi qua các liên kết tượng trưng).

Ở trên, bạn sẽ nhận thấy sự cần thiết phải đảm bảo không có phần mở rộng nào được hiểu là một tùy chọn. Đối với điều đó, bạn sẽ làm:

ls -- *

Hoặc là:

ls ./*

Có một số lệnh (không thành vấn đề ls) trong đó thứ hai là thích hợp hơn vì ngay cả với --một số tên tệp có thể được xử lý đặc biệt. Đó là trường hợp của -đối với hầu hết các tiện ích văn bản, cdpushdvà tên tệp chứa các =ký tự cho awkví dụ. Chuẩn bị ./cho tất cả các đối số loại bỏ ý nghĩa đặc biệt của chúng (ít nhất là đối với các trường hợp được đề cập ở trên).

Cũng cần lưu ý rằng hầu hết các shell đều có một số tùy chọn ảnh hưởng đến hành vi toàn cầu hóa (như liệu các tệp chấm có bị bỏ qua hay không, thứ tự sắp xếp, phải làm gì nếu không khớp ...), xem thêm $FIGNOREtham số trongksh

Ngoài ra, trong mỗi vỏ nhưng csh, tcsh, fishzsh, nếu mẫu globbing không phù hợp với bất kỳ tập tin, mô hình được thông qua như là một đối số chưa giãn nở đó gây nhầm lẫn và có thể lỗi. Chẳng hạn, nếu không có tệp không bị ẩn trong thư mục hiện tại

ls *

Sẽ thực sự gọi lsvới hai đối số ls*. Và vì không có tệp nào cả, vì vậy không ai gọi *, bạn sẽ thấy một thông báo lỗi từ ls (không phải vỏ) như : ls: cannot access *: No such file or directory, được biết là khiến mọi người nghĩ rằng đó lsthực sự là mở rộng các khối.

Vấn đề thậm chí còn tồi tệ hơn trong các trường hợp như:

rm -- *.[ab]

Nếu không có *.acũng không *.btập tin trong thư mục hiện hành, sau đó bạn có thể kết thúc việc xóa một tập tin gọi là *.[ab]do nhầm lẫn ( csh, tcshzshsẽ báo cáo một không phù hợp lỗi và sẽ không gọi rm(và fishkhông hỗ trợ các [...]ký tự đại diện)).

Nếu bạn muốn vượt qua một chữ *để ls, bạn phải trích dẫn rằng *nhân vật một cách nào đó như trong ls \*hay ls '*'hay ls "*". Trong các shell giống như POSIX, có thể vô hiệu hóa toàn cầu hóa bằng cách sử dụng set -o noglobhoặc set -f(cái sau không hoạt động zshtrừ khi trong sh/ kshmô phỏng).


Mặc dù (*/)#luôn được hỗ trợ, nhưng lần đầu tiên nó là tay ngắn như ..../trong zsh-2.0 (và có khả năng trước đó), sau đó là ****/2.1 trước khi có được hình thức dứt khoát **/vào năm 2.2 (đầu năm 1992)


22
Câu trả lời thực sự tuyệt vời!
Andrea Corbellini

7
Một ví dụ tốt đẹp là find -name *. Đặc biệt với các mẫu phức tạp hơn, nếu có chính xác một kết quả khớp trong thư mục hiện tại, mọi người thường sẽ không nhận ra họ không chuyển dấu hoa thị tới find.
13 lúc 10:30

Tôi tiếp tục cho 1, tôi thực sự vui mừng khi thấy Stephane Chazelas hoạt động ở đây trên unix.stackexchange.com ! Những đóng góp to lớn, Stephane, như mọi khi!
Dimitre Radoulov

1
Trong cá, *.[ab]sẽ cố gắng xóa mọi thứ kết thúc bằng .[ab]. [không đặc biệt ở cá.
Konrad Borowski

35

Lệnh lsmặc định là ls .: Liệt kê tất cả các mục trong thư mục hiện tại .

Lệnh này ls *có nghĩa là 'chạy ls khi mở rộng *mẫu shell'

Các *mẫu được xử lý bằng vỏ, và mở rộng cho tất cả các mục trong thư mục hiện hành, ngoại trừ những người bắt đầu với một .. Nó sẽ đi sâu một cấp.

Việc giải thích các mẫu kép hoặc gấp ba *phụ thuộc vào lớp vỏ thực tế được sử dụng.

*là ký tự đại diện khớp với 0 ký tự trở lên. Một số shell hiện đại sẽ tái diễn thành các thư mục con khi nhìn thấy **mẫu.


17
Ngoại trừ việc thêm vào * để thêm một cái gì đó, xem câu trả lời khác giải thích toàn cầu. Cũng cần phải làm rõ rằng ls không liên quan gì đến các dấu sao, nó không bao giờ vượt qua bất kỳ dấu hoa thị nào cả. Chạy echo ls *để xem những gì sẽ được thực hiện khi bạn viết ls *.
21 giờ 49

12

Bạn có thể làm sáng tỏ toàn bộ quá trình bằng cách gõ echothay vì lstrước tiên, để xem lệnh mở rộng thành gì:

$ echo *
Applications Downloads Documents tmp.html

Vì vậy, trong trường hợp này, ls *mở rộng đếnls Applications Downloads Documents tmp.html

$ echo **
Applications Downloads Documents tmp.html

$ echo ***
Applications Downloads Documents tmp.html

Vì vậy, không có thay đổi. Điều này giả định rằng bạn đang sử dụng bashlàm vỏ của mình - hầu hết mọi người là và các vỏ khác nhau có hành vi khác nhau. Nếu bạn đang sử dụng ashhay cshhay kshhay zsh, bạn có thể mong đợi điều cần làm việc khác nhau. Đó là điểm có vỏ khác nhau.

Vì vậy, hãy thử một cái gì đó khác (vẫn với bash) để chúng tôi có ý tưởng về *toán tử globalbing ( ) có thể làm cho chúng tôi. Ví dụ: chúng ta có thể lọc theo một phần của tên:

$ echo D*
Downloads Documents

Và thật thú vị, một dấu gạch chéo là một phần ngầm của bất kỳ tên thư mục nào. Vì vậy, */sẽ chỉ mang lại các thư mục (và các liên kết tượng trưng đến các thư mục):

$ echo */
Applications/ Downloads/ Documents/

Và chúng ta có thể thực hiện một số bộ lọc ở nhiều cấp độ bằng cách đặt dấu gạch chéo ở giữa:

$ echo D*/*/
Documents/Work/ /Documents/unfinished/

Downloadsthư mục không chứa bất kỳ thư mục con nào, nó không kết thúc ở đầu ra. Điều này rất hữu ích cho việc kiểm tra các tập tin bạn muốn. Tôi sử dụng các lệnh như thế này mọi lúc:

$ ls -l /home/*/public_html/wp-config.php

Danh sách này, nếu có, tất cả các wp-config.phptệp tồn tại ở cấp độ cơ sở của bất kỳ public_htmlthư mục nào của người dùng . Hoặc có lẽ để được hoàn thiện hơn:

$ find /home/*/public_html/ -name wp-config.php

Điều này sẽ tìm thấy bất kỳ wp-config.phptệp nào trong bất kỳ public_htmlthư mục nào của người dùng hoặc bất kỳ thư mục con nào của họ, nhưng nó sẽ hoạt động hiệu quả hơn là find /home/ -name wp-config.phpvì nó sẽ không kiểm tra bất cứ thứ gì ngoại trừ các public_htmlthư mục cho mỗi người dùng.


1
"Điều này giả sử bạn đang sử dụng bashlàm vỏ của mình" ← và sao đó không được bật. shopt -s globstarvà thử nó một lần nữa ...
njsg

Một cách khác để làm sáng tỏ là set -xsẽ bắt đầu in lệnh "thực tế" được thực thi mỗi lần (tắt bằng set +x).
ShreevatsaR

10

Trong một số shell, bao gồm bash 4.x với globstartùy chọn được bật, **sẽ thực hiện một thư mục phù hợp với đệ quy, giảm dần. Dấu hoa thị bổ sung không sửa đổi thêm hoạt động này.


1
Như tôi đã nói trong câu trả lời của mình, hãy cẩn thận trái với ksh93zsh, bashkhông liên kết ngang trong đệ quy thường không mong muốn.
Stéphane Chazelas

Điều đó hiện đã được sửa trong bash 4.3
Stéphane Chazelas

1

Nếu bạn muốn "lặn sâu", hãy sử dụng tùy chọn ls -R (đệ quy) hoặc sử dụng find, như vậy:

find . -ls

"find" sẽ lặn xuống dưới cùng của cây thư mục (cũng như 'ls -R') và có nhiều tùy chọn khác, như liệt kê các thư mục (-type d), chỉ các tệp (-type f) hoặc hiển thị các tệp có khác đặc điểm (không có người dùng trong / etc / passwd, quyền cụ thể và nhiều hơn nữa). "Tìm" cũng có phần an toàn hơn trong việc tạo kịch bản (do quy tắc tạo khối không nhất quán giữa các shell, cũng như các lối thoát đặc biệt cho các tệp có dấu gạch ngang, v.v.).

shell wildcard globalbing sẽ không hoạt động chỉ với dấu hoa thị '*' trên dotfiles. Để chỉ liệt kê dotfiles, hãy sử dụng:

ls .??*


-1

Thêm * không thêm mức độ sâu. Nhưng nếu bạn cố gắng

 ls */*/*

- bạn sẽ nhận được danh sách các thư mục con của các thư mục con trong các thư mục trong thư mục hiện tại ...


Sai lầm. Tùy thuộc vào vỏ, *s thêm sẽ thêm mức độ sâu.
njsg

Vì vậy, lớp vỏ nào sẽ thêm mức độ sâu trên các ngôi sao phụ?
VB9-UANIC

Một số. Bao gồm GNU bashvới tùy chọn globalstar, vỏ korn và zsh. Và có thể những người khác, tôi đoán. unix.stackexchange.com/a/62665/14831
njsg

-1

Nắm bắt chính của tôi là tiếng vang ** / *. Ext nói chung sẽ ...

Có thể hoặc không thể: liệt kê một tệp .ext trong thư mục hiện tại

Tháng 5 hoặc tháng 5 không: bao gồm. *. Ext file

Nói chung, tôi thích biểu thức toàn cầu là '** /' và có thể dẫn đến một chuỗi null (không có thư mục con). Đây là cách tôi chuyển đổi các biểu thức toàn cầu trong đầu vào chương trình. Tất nhiên tôi không chắc chắn có ý kiến ​​giải thích điều này trong các ví dụ sử dụng.

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.