Câu trả lời:
ls
liệ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. ls
khô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 glob
sẽ 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
, -l
và foo bar
, *
sẽ được mở rộng bằng vỏ để hai đối số để truyền đến ls
: -l
và foo 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, ls
lệnh (có thể sẽ được thực thi từ /bin/ls
tra 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, ls
sẽ 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, đã zsh
giớ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 (*/)#
và ***/
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).
bash
sao chép ksh93
mộ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-glob
tù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 zsh
và hai phần mở rộng của chính nó: .**
và .***
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
, **/*.c
sẽ phù hợp a/b/c.c
nhưng không a.c
, trong khi a**.c
sẽ phù hợp a.c
và ab/c/d.c
và zsh
's **/.*
ví dụ đã được viết .* **/.*
. Ở đó, ***
được hiểu như **
sau bởi *
vì vậy giống như **
.
tcsh
cũng đã thêm một globstar
tùy chọn trong V6.17.01 (tháng 5 năm 2010) và hỗ trợ cả hai **
và ***
à la zsh
.
Vì vậy, trong tcsh
, bash
và ksh93
, (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 tcsh
có globstar
, và giống như *
trong bash
và ksh93
(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, cd
và pushd
và tên tệp chứa các =
ký tự cho awk
ví 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 $FIGNORE
tham số trongksh
Ngoài ra, trong mỗi vỏ nhưng csh
, tcsh
, fish
và zsh
, 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 ls
với hai đối số ls
và *
. 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 đó ls
thự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ó *.a
cũng không *.b
tậ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
, tcsh
và zsh
sẽ báo cáo một không phù hợp lỗi và sẽ không gọi rm
(và fish
khô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 noglob
hoặc set -f
(cái sau không hoạt động zsh
trừ khi trong sh
/ ksh
mô 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)
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
.
*.[ab]
sẽ cố gắng xóa mọi thứ kết thúc bằng .[ab]
. [
không đặc biệt ở cá.
Lệnh ls
mặ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.
*
để 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 *
.
Bạn có thể làm sáng tỏ toàn bộ quá trình bằng cách gõ echo
thay vì ls
trướ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 bash
là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 ash
hay csh
hay ksh
hay 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/
Vì Downloads
thư 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.php
tệp tồn tại ở cấp độ cơ sở của bất kỳ public_html
thư 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.php
tệp nào trong bất kỳ public_html
thư 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.php
vì nó sẽ không kiểm tra bất cứ thứ gì ngoại trừ các public_html
thư mục cho mỗi người dùng.
bash
làm vỏ của mình" ← và sao đó không được bật. shopt -s globstar
và thử nó một lần nữa ...
set -x
sẽ bắt đầu in lệnh "thực tế" được thực thi mỗi lần (tắt bằng set +x
).
Trong một số shell, bao gồm bash 4.x với globstar
tù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.
ksh93
và zsh
, bash
không liên kết ngang trong đệ quy thường không mong muốn.
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 .??*
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 ...
*
s thêm sẽ thêm mức độ sâu.
bash
vớ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
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.