Đệ quy toàn cầu?


80

Tôi muốn viết một cái gì đó như thế này:

$ ls **.py

để có được tất cả tên tệp .py, hãy đệ quy một hệ thống phân cấp thư mục.

Ngay cả khi có các tệp .py để tìm, shell (bash) cho đầu ra này:

ls: cannot access **.py: No such file or directory

Bất cứ cách nào để làm những gì tôi muốn?

EDIT: Tôi muốn xác định rằng tôi không quan tâm đến trường hợp cụ thể ls, nhưng câu hỏi là về cú pháp toàn cầu.

Câu trả lời:


98

Để thực hiện các phép lặp đệ quy trong bash, bạn cần globstarcó tính năng từ bash phiên bản 4 trở lên.

Từ trang bash:

globstar
    If set, the pattern ** used in a pathname expansion context will
    match all files and zero or more directories and subdirectories.
    If the pattern is followed by a /, only directories and
    subdirectories match.

Đối với mẫu ví dụ của bạn:

shopt -s globstar
ls **/*.py

2
Tôi cũng khuyên bạn nên bậtnullglob
glenn jackman

6
@glennjackman Nhưng trước khi kích hoạt nullglob, tôi sẽ khuyên bạn nên đọc các cảnh báo sau .
Serge Stroobandt

2
^ Cảnh báo đã chuyển đến đây .
tôi

1
Với bash 3.2, wc -l {**,.}/*.pyhoạt động rất tốt
Raphael

@Raphael Tôi đã kiểm tra lại các ghi chú phát hành và nó chắc chắn nói rằng nó đã được giới thiệu trong 4.0. Có lẽ bạn phân phối đã backport một bản vá cho nó? IIRC RHEL 5 đã đưa ra một số tính năng. Cũng cần lưu ý, đã 9 năm kể từ khi bash 4 được phát hành ...
jordanm

10
find . -name '*.py'

** không làm gì hơn một *, cả hai đều hoạt động trong thư mục hiện tại


Hấp dẫn. Mặc dù vậy, tôi tập trung nhiều hơn vào cú pháp toàn cầu, bởi vì tôi phải sử dụng nó trong một tệp cấu hình (bao gồm chỉ thị). Tôi không cần một danh sách các tập tin.
Paolo

2
@Doug O'Neal, điều đó không còn đúng nữa. bash hiện đã sao chép tính năng zsh đó (mặc dù nó đã sử dụng cú pháp gần với ksh93 và giống như ksh, nhưng không hỗ trợ vòng loại toàn cầu của zsh nhưng điều đó hạn chế tính hữu dụng của nó)
Stéphane Chazelas

Có rất nhiều điều bạn có thể làm findnếu không có bash 4. Ví dụ: yourcommand `find . -name '*.py'`(lưu ý các backticks); find . -name '*.py' -exec yourcommand {} \;.
Sao Hỏa

5

Vì Bash 4 (bao gồm cả zsh), một tùy chọn toàn cầu mới ( globstar) đã được thêm vào để xử lý mẫu **khác nhau khi được đặt.

Nó phù hợp với mẫu ký tự đại diện và trả về tên tệp và thư mục khớp với nhau bằng cách thay thế mẫu ký tự đại diện trong lệnh bằng các mục khớp.

Thông thường khi bạn sử dụng **, nó hoạt động tương tự *, nhưng nó đệ quy tất cả các thư mục theo cách đệ quy (như một vòng lặp).

Để xem nếu nó được kích hoạt, hãy kiểm tra nó bằng cách shopt globstar(trong kịch bản, sử dụng shopt -q globstar).

Ví dụ **.pynày chỉ hoạt động cho thư mục hiện tại, vì nó không trả về danh sách các thư mục có thể được đệ quy, vì vậy đó là lý do tại sao bạn cần sử dụng nhiều ký tự đại diện cấp thư mục **/*.py, để nó có thể đi sâu hơn.

Vui lòng tìm trên SO vài bài kiểm tra cú pháp mà tôi đã làm để tìm tất cả các tệp đệ quy.

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.