Tôi biết **/*.ext
mở rộng cho tất cả các tệp trong tất cả các thư mục con phù hợp *.ext
, nhưng một bản mở rộng tương tự bao gồm tất cả các tệp như vậy trong thư mục hiện tại là gì?
Câu trả lời:
Điều này sẽ hoạt động trong Bash 4:
ls -l {,**/}*.ext
Để dấu sao kép hoạt động, bạn globstar
cần đặt tùy chọn (mặc định: bật):
shopt -s globstar
Từ man bash
:
sao cầu Nếu được đặt, mẫu ** được sử dụng trong con đường mở rộng tên tệp‐ văn bản sẽ khớp với một tệp và không hoặc nhiều thư mục và các thư mục con. Nếu mẫu được theo sau bởi dấu /, chỉ thư mục và thư mục con khớp nhau.
Bây giờ tôi đang tự hỏi liệu có thể đã từng có lỗi trong quá trình xử lý hình cầu không, bởi vì bây giờ sử dụng đơn giản là ls **/*.ext
tôi nhận được kết quả chính xác.
Bất chấp điều đó, tôi đã xem xét phân tích mà kenorb đã thực hiện bằng cách sử dụng kho VLC và tìm thấy một số vấn đề với phân tích đó và trong câu trả lời của tôi ngay lập tức ở trên:
Các so sánh với đầu ra của find
lệnh không hợp lệ vì việc chỉ định -type f
không bao gồm các loại tệp khác (cụ thể là các thư mục) và các ls
lệnh được liệt kê có khả năng làm được. Ngoài ra, một trong các lệnh được liệt kê, ls -1 {,**/}*.*
- dường như dựa trên lệnh của tôi ở trên, chỉ xuất ra các tên bao gồm dấu chấm cho những tệp nằm trong thư mục con. Câu hỏi của OP và câu trả lời của tôi bao gồm một dấu chấm vì thứ đang được tìm kiếm là các tệp có phần mở rộng cụ thể.
Tuy nhiên, quan trọng nhất là có một vấn đề đặc biệt khi sử dụng ls
lệnh với mẫu hình sao cầu **
. Nhiều bản sao phát sinh do mẫu được Bash mở rộng thành tất cả các tên tệp (và tên thư mục) trong cây đang được kiểm tra. Sau phần mở rộng, ls
lệnh liệt kê từng người trong số họ và nội dung của chúng nếu chúng là thư mục.
Thí dụ:
Trong thư mục hiện tại của chúng tôi là thư mục con A
và nội dung của nó:
A
└── AB
└── ABC
├── ABC1
├── ABC2
└── ABCD
└── ABCD1
Trong cây đó, **
mở rộng thành "AA / AB A / AB / ABC A / AB / ABC / ABC1 A / AB / ABC / ABC2 A / AB / ABC / ABCD A / AB / ABC / ABCD / ABCD1" (7 mục) . Nếu bạn làm như vậy thì echo **
đó là đầu ra chính xác mà bạn nhận được và mỗi mục nhập được thể hiện một lần. Tuy nhiên , nếu bạn làm vậy, ls **
nó sẽ xuất ra một danh sách của từng mục nhập đó. Vì vậy, về cơ bản nó được ls A
theo sau bởi ls A/AB
, v.v., vì vậy A/AB
được hiển thị hai lần. Ngoài ra, ls
sẽ đặt đầu ra của từng thư mục con riêng biệt:
...
<blank line>
directory name:
content-item
content-item
Vì vậy, sử dụng wc -l
đếm tất cả các dòng trống đó và tiêu đề phần tên thư mục sẽ đẩy số lượng ra xa hơn.
Đây là một lý do khác tại sao bạn không nên phân tích cú phápls
.
Do kết quả của phân tích sâu hơn này, tôi khuyên bạn không nên sử dụng mẫu hình sao cầu trong bất kỳ trường hợp nào ngoài việc lặp lại một cây tệp theo cách sau:
for entry in **
do
something "$entry"
done
Để so sánh cuối cùng, tôi đã sử dụng kho lưu trữ mã nguồn Bash mà tôi có sẵn và thực hiện điều này:
shopt -s globstar dotglob
diff <(echo ** | tr ' ' '\n') <(find . | sed 's|\./||' | sort)
0a1
> .
Tôi đã sử dụng tr
để thay đổi dấu cách thành dòng mới chỉ hợp lệ ở đây vì không có tên nào bao gồm dấu cách. Tôi đã sử dụng sed
để loại bỏ hàng đầu ./
từ mỗi dòng đầu ra từ find
. Tôi đã sắp xếp đầu ra find
vì nó thường không được sắp xếp và việc mở rộng các quả địa cầu của Bash đã được sắp xếp. Như bạn có thể thấy, đầu ra duy nhất từ diff
thư mục hiện tại là .
đầu ra của find
. Khi tôi đã làmls ** | wc -l
, đầu ra có gần gấp đôi số dòng.
globstar
được mặc địnhoff
**/*.ext
phải là đủ mặc dù. Ngoài ra, bạn sẽ không có các tệp ẩn trừ khi bạn shopt -s dotglob
.
globstar
: shopt -u globstar
.
**/*.ext
sẽ không đủ
Điều này sẽ in tất cả các tệp trong thư mục hiện tại và các thư mục con của nó kết thúc bằng '.ext'.
find . -name '*.ext' -print
Bạn có thể sử dụng: **/*.*
để bao gồm tất cả các tệp một cách đệ quy (bật bằng cách shopt -s globstar
:).
Vui lòng xem bên dưới thử nghiệm các biến thể khác và cách chúng hoạt động.
Thư mục thử nghiệm với 3472 tệp trong thư mục kho lưu trữ VLC mẫu :
(Tổng số 3472 tệp được tính theo find . -type f | wc -l
:)
ls -1 **/*.*
- trả về 3338ls -1 {,**/}*.*
- trả về 3341 (theo đề xuất của Dennis )ls -1 {,**/}*
- trả về 8265ls -1 **/*
- trả về 7817, ngoại trừ các tệp ẩn (theo đề xuất của Dennis )ls -1 **/{.[^.],}*
- trả về 7869 (theo đề xuất của Dennis )ls -1 {,**/}.?*
- trả lại 15855ls -1 {,**/}.*
- trả về 20321Vì vậy, tôi nghĩ rằng phương pháp gần nhất để liệt kê tất cả các tệp một cách đệ quy là ví dụ đầu tiên ( **/*.*
) theo nhận xét của gniourf-gniourf (giả sử các tệp có phần mở rộng thích hợp hoặc sử dụng phần mở rộng cụ thể), vì ví dụ thứ hai cung cấp thêm một số bản sao như bên dưới :
$ diff -u <(ls -1 {,**/}*.*) <(ls -1 **/*.*)
--- /dev/fd/63 2015-04-19 15:25:07.000000000 +0100
+++ /dev/fd/62 2015-04-19 15:25:07.000000000 +0100
@@ -1,6 +1,4 @@
COPYING.LIB
-COPYING.LIB
-Makefile.am
Makefile.am
@@ -45,7 +43,6 @@
compat/tdestroy.c
compat/vasprintf.c
configure.ac
-configure.ac
và cái kia tạo ra nhiều bản sao hơn nữa.
Để bao gồm các tệp ẩn, hãy sử dụng: shopt -s dotglob
(tắt bằng cách shopt -u dotglob
). Nó không được khuyến khích, vì nó có thể ảnh hưởng đến các lệnh như mv
hoặc rm
và bạn có thể vô tình xóa các tệp sai.
**/*.*
) đầy đủ thông tin và hoạt động tốt nhất. Câu trả lời được chấp nhận gây ra trùng lặp các mục trong thư mục trên cùng. Mô hình làm việc của tôi là:"${path}"**/*.*
$ find . -type f
Điều đó sẽ liệt kê tất cả các tệp trong thư mục hiện tại. Sau đó, bạn có thể thực hiện một số lệnh khác trên đầu ra bằng -exec
$find . -type f -exec grep "foo" {} \;
Điều đó sẽ gửi từng tệp từ tìm thấy cho chuỗi "foo".
find . -type f
áp dụng đệ quy với thư mục gốc tại thư mục hiện tại, không chỉ cho thư mục hiện tại.
Tại sao không chỉ sử dụng mở rộng dấu ngoặc nhọn để bao gồm cả thư mục hiện tại?
./{*,**/*}.ext
Mở rộng Brace xảy ra trước khi mở rộng toàn cầu, vì vậy bạn có thể thực hiện hiệu quả những gì bạn muốn với các phiên bản bash cũ hơn và có thể bỏ qua việc phát triển mạnh mẽ với cầu sao trong các phiên bản mới hơn.
Ngoài ra, nó được coi là một phương pháp hay trong bash để bao gồm phần dẫn đầu ./
trong các mẫu hình cầu của bạn.
**/*.ext
. Bạn có chắc nó làm việc cho bạn?