Tìm danh sách các thư mục sâu một cấp từ thư mục phù hợp


13

Tôi đang cố gắng để có được một danh sách các thư mục được chứa trong một thư mục cụ thể.

Cho các thư mục ví dụ sau:

foo/bar/test
foo/bar/test/css
foo/bar/wp-content/plugins/XYZ
foo/bar/wp-content/plugins/XYZ/js
foo/bar/wp-content/plugins/XYZ/css
baz/wp-content/plugins/ABC
baz/wp-content/plugins/ABC/inc
baz/wp-content/plugins/ABC/inc/lib
baz/wp-content/plugins/DEF
bat/bar/foo/blog/wp-content/plugins/GHI

Tôi muốn một lệnh sẽ trở lại:

XYZ
ABC
DEF
GHI

Về cơ bản, tôi đang tìm các thư mục bên trong wp-content / plugin /

Việc sử dụng findđã giúp tôi gần nhất, nhưng tôi không thể sử dụng -maxdepth, vì thư mục nằm cách xa nơi tôi đang tìm kiếm.

Chạy sau đây trả về tất cả các thư mục con, đệ quy.

find -type d -path *wp-content/plugins/*

foo/bar/wp-content/plugins/XYZ
foo/bar/wp-content/plugins/XYZ/js
foo/bar/wp-content/plugins/XYZ/css
baz/wp-content/plugins/ABC
baz/wp-content/plugins/ABC/inc
baz/wp-content/plugins/ABC/inc/lib
baz/wp-content/plugins/DEF
bat/bar/foo/blog/wp-content/plugins/GHI

Câu trả lời:


14

Chỉ cần thêm một -pruneđể các thư mục tìm thấy không được hạ xuống:

find . -type d -path '*/wp-content/plugins/*' -prune -print

Bạn cần phải trích dẫn rằng *wp-content/plugins/*đó cũng là một vỏ toàn cầu.

Nếu bạn chỉ muốn các tên thư mục trái ngược với đường dẫn đầy đủ của chúng, với GNU find, bạn có thể thay thế -printbằng -printf '%f\n'hoặc giả sử các đường dẫn tệp không chứa các ký tự dòng mới, chuyển đầu ra của lệnh trên sang awk -F / '{print $NF}'hoặc sed 's|.*/||'(cũng giả sử các đường dẫn tệp chứa chỉ các ký tự hợp lệ).

Với zsh:

printf '%s\n' **/wp-content/plugins/*(D/:t)

**/là bất kỳ mức độ thư mục con (tính năng có nguồn gốc ở zshtrong nighties sớm, và bây giờ tìm thấy trong hầu hết các tiện ích khác thích ksh93, tcsh, fish, bash, yashmặc dù thường theo một số tùy chọn), (/)để chỉ chọn các file kiểu thư mục , Dbao gồm ẩn (dot) người, :tđể lấy đuôi (tên tập tin).


Phát hiện này sẽ chuyển đổi dòng mới trong dirs sang a ?. Đối với bash, (như được gắn thẻ trong câu hỏi) điều này hoạt động .
sorontar

@sorontar, findviệc triển khai tạo ra một ?hoặc bất kỳ ký tự thay thế hoặc bất kỳ hình thức thoát nào cho các ký tự không in được chỉ làm điều đó khi đầu ra đi đến một thiết bị đầu cuối, không phải khi nó đi đến một đường ống như ở đây.
Stéphane Chazelas

Lệnh đầu tiên (và duy nhất không phải zsh) trong câu trả lời của bạn không có đường ống, nó là lệnh tôi đã kiểm tra và là lệnh thay đổi dòng mới. Khi được dẫn, như bạn đã nói: "giả sử đường dẫn tệp không chứa ký tự dòng mới", vì vậy, bạn đã thừa nhận rằng nó cũng thất bại với dòng mới.
sorontar

@sorontar, xin lỗi, tôi nghĩ rằng bạn đã bình luận về phần thứ hai để nói rằng nó sẽ hoạt động tốt vì các dòng mới sẽ được thoát nên sẽ không phá vỡ giả định mà chúng tôi đưa ra sed/ awkrằng tất cả các tệp đều nằm trên một dòng. Bây giờ, Người ta có thể lập luận rằng nhận được một ABC?BCDhoặc ABC\nBCDcho đầu ra tương tác / thiết bị đầu cuối sẽ hữu ích hơn so với nhận hai ABCBCDdòng cho một thư mục được gọi $'ABC\nBCD. Đó là ở cấp độ trình bày của người dùng, chúng tôi cũng có thể chỉ ra rằng đối với một tệp được gọi $'AB\bC', khi đầu ra đi đến một thiết bị đầu cuối, bạn sẽ thấy ACmà không có sự ?thay thế như vậy ...
Stéphane Chazelas

Tìm với -prune và sử dụng printf để sửa đổi định dạng đầu ra đã cho tôi chính xác những gì tôi đang yêu cầu. Hoàn hảo - cảm ơn!
Nick

4

Bash-ically:

shopt -s globstar
printf "%s\n" **/wp-content/plugins/*

in:

bat/bar/foo/blog/wp-content/plugins/GHI
baz/wp-content/plugins/ABC
baz/wp-content/plugins/DEF
foo/bar/wp-content/plugins/XYZ

hoặc là

shopt -s globstar
for d in **/wp-content/plugins/*; do printf "%s\n" ${d##*/}; done

in:

GHI
ABC
DEF
XYZ

Không, điều đó cũng sẽ in các tập tin bên trong các thư mục. Xin vui lòng đọc câu trả lời của tôi.
sorontar

Điểm tốt; cảm ơn bạn! Tôi đã tạo lại cấu trúc thư mục của họ, nhưng không đặt các tệp kiểm tra trong đó.
Jeff Schaller

4

Bạn có thể có findrecurse, loại:

find / -type d -path *wp-content/plugins -exec find {} -maxdepth 1 -mindepth 1 -type d \;

3

Đối với Bash: Simple (hoạt động cho các tệp / thư mục có dấu cáchdòng mới ):

shopt -s globstar                    # allow ** for several dirs.
a=(**/wp-content/plugins/*/)         # capture only wanted dirs.
a=("${a[@]%/}")                      # remove trailing slash (dirs) `/`.
printf '%s\n' "${a[@]##*/}"          # print only the last dir name.

Sẽ in:

GHI
ABC
DEF
XYZ

Ngay cả khi có các tập tin được tạo ra.


Lưu ý rằng nó không nhìn vào các thư mục ẩn, bỏ qua các tệp ẩn (xem dotglobtùy chọn nếu không mong muốn) và bao gồm các liên kết tượng trưng đến các thư mục bên cạnh các thư mục ( **cũng sẽ duyệt qua các liên kết tượng trưng trong bash 4.2 trở về trước).
Stéphane Chazelas

@ StéphaneChazelas ẩn tập tin? Câu hỏi không hỏi, chỉ có dirs. Có, các thư mục ẩn có thể được chọn độc lập (như một tính năng, nếu muốn). Và vâng, symlink không nằm ngang trong phiên bản bash hiện tại.
sorontar

1
xin đừng coi ý kiến ​​của tôi là sự gây hấn. Tôi nêu lên câu trả lời của bạn và thêm một ghi chú bên dưới để chỉ ra một số sự thật về nó không nhất thiết phải rõ ràng. findkhông loại trừ bất kỳ tập tin. Globs loại trừ các tập tin dấu chấm, đáng để chỉ ra là một sự khác biệt giữa hai.
Stéphane Chazelas

3

Các treelệnh được thiết kế chính xác cho mục đích này. Độ sâu có thể được kiểm soát với -Lcờ. Dưới đây là một ví dụ trên trang Wordpress địa phương mà tôi duy trì:

$ tree -L 1 wp-content/
wp-content/
├── index.php
├── plugins
└── themes

2 directories, 1 file

$ tree -L 2 wp-content/
wp-content/
├── index.php
├── plugins
   ├── akismet
   ├── contact-form-7
   ├── index.php
   └── wordpress-seo
└── themes
    ├── index.php
    ├── twentyfifteen
    └── twentysixteen

11 directories, 3 files

$ tree -L 1 wp-content/plugins/
wp-content/plugins/
├── akismet
├── contact-form-7
├── index.php
└── wordpress-seo

5 directories, 1 file

1

Dựa trên câu trả lời của DopeGhoti, về vòng lặp khớp:

find / -type d -iregex '.*/wp-content/plugins' -print0 | while read -r -d $'\0' D; do
    find "$D" -maxdepth 2 -mindepth 1
done

Lý do để thực hiện theo cách này là bạn có thể thấy nó khó hiểu / cồng kềnh với nhiều -exec', trong khi vẫn tránh được các vấn đề với tên tệp đặc biệt có chứa \ n' ', v.v. -print0 sẽ sử dụng dấu tách null giữa các kết quả.


0

Dựa trên những gì bạn bắt đầu:

find -type d -path *wp-content/plugins/* | egrep -o "wp-content/plugins/[^/]+($|/)" | sed -r "s~wp-content/plugins/([^/]+)($|/)~\1~" | uniq  

egrep lấy * wp-content / plugin / * và bất kỳ ký tự nào cho đến dấu gạch chéo tiếp theo / hoặc cuối dòng $ - bao gồm phần bạn muốn.

sed , với dấu phân cách ~, chọn phần bạn muốn bằng cách sử dụng bộ dấu ngoặc đơn đầu tiên () và sử dụng \ 1 (những gì bạn muốn) làm thay thế mọi thứ

uniq lọc ra kết quả trùng lặp

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.