tìm: prune không bỏ qua đường dẫn được chỉ định


13

Tôi cần loại trừ .gitkhỏi findtìm kiếm của tôi . Để đạt được điều đó, tôi đang sử dụng công -path ./.git -prunetắc:

$ find . -path ./.git -prune -o \( -type f -o -type l -o -type d \) | grep '.git'
./.git

Tuy nhiên, mặc dù điều này bỏ qua nội dung của thư mục .git, nhưng nó liệt kê chính thư mục đó. Nó hoạt động khi tôi thêm-path ./.git -prune -o -print -a

find . -path ./.git -prune -o -print -a \( -type f -o -type l -o -type d \) | grep '.git'

Tại sao điều này là cần thiết. Tôi nghĩ rằng cả hai lệnh nên có cùng một đầu ra. Cú pháp thứ hai khá xấu xí.


4
Bạn cần một -print, nếu không thì ngầm -printáp dụng cho toàn bộ điều kiện
Stéphane Chazelas


Câu trả lời:


3

Các mantrang cho findcung cấp cho:

-prune True; if the file is a directory, do not  descend  into  it.  If
      -depth  is  given,  false;  no  effect.  Because -delete implies
      -depth, you cannot usefully use -prune and -delete together.

Vì vậy, trong ví dụ đầu tiên, nó không phải -path ./.git -prunelà không đúng sự thật và do đó hành động mặc định ( -print) sẽ không được gọi, do đó dòng được in.


22

Tôi đã bối rối về lý do tại sao các thư mục được cắt tỉa cũng được in bằng findlệnh và một số chi tiết phức tạp khác về cách -prunelàm việc, nhưng có thể tìm ra nó với một vài ví dụ.

Để chạy các ví dụ dưới đây, tạo các thư mục và tệp sau đây.

mkdir aa
mkdir bb
touch file1
touch aa/file1
touch bb/file3

Để tạo cấu trúc này:

$ tree

.
├── aa
   └── file1
├── bb
   └── file3
└── file1

Bây giờ sử dụng find để tìm các thư mục có tên aa. Không có vấn đề ở đây.

$ find . -type d -name aa
./aa

Tìm kiếm tất cả các thư mục khác ngoài aa và chúng tôi nhận được thư mục hiện tại ../bb, cũng có ý nghĩa.

$ find . -type d ! -name aa
.
./bb

Cho đến nay rất tốt, nhưng khi chúng tôi sử dụng -prune, tìm trả về thư mục chúng tôi đang cắt, điều này ban đầu làm tôi bối rối vì tôi hy vọng nó sẽ trả về tất cả các thư mục khác chứ không phải thư mục được cắt tỉa.

$ find . -type d -name aa -prune
./aa

Lý do tại sao nó trả về thư mục được cắt tỉa được giải thích, không phải trong -prunephần của các trang man như được nêu trong câu trả lời của Timo , mà trong EXPRESSIONSphần:

Nếu biểu thức không chứa hành động nào khác -prune,  -printđược thực hiện trên tất cả các tệp mà biểu thức là đúng.

điều đó có nghĩa là, vì biểu thức khớp với aatên thư mục, nên biểu thức sẽ đánh giá là đúng và nó sẽ được in vì tìm thấy thêm một -printdấu chấm ở cuối toàn bộ lệnh. -printTuy nhiên, nó sẽ không thêm một hành động nếu bạn cố tình thêm hành động -o -printvào cuối:

find . -type d -name aa -prune -o -print
.
./file1
./bb
./bb/file3

Ở đây, lệnh find KHÔNG thêm ẩn -printnữa, và vì vậy thư mục chúng ta đang cắt tỉa ( aa) sẽ không được in.

Vì vậy, cuối cùng, nếu chúng ta thêm một mệnh đề tìm kiếm các tệp có mẫu tên tệp file*sau -o, thì bạn phải đặt một -printmệnh đề ở cuối mệnh đề thứ hai như thế này:

find . \( -type d -name aa -prune \) -o \( -type f -name 'file*' -print \)
./file1
./bb/file3

Lý do tại sao điều này hoạt động giống nhau: Nếu bạn không đặt -printmệnh đề thứ hai, thì vì không có hành động nào khác ngoài -prunehành động, find sẽ -printtự động thêm vào lệnh END, khiến -prunemệnh đề in ra thư mục cắt tỉa:

find . \( \( -type d -name aa -prune \) -o \( -type f -name 'file*' \) \) -print
./aa
./file1
./bb/file3

Nói chung, bạn cần đặt -printlệnh trong mệnh đề thứ hai. Nếu bạn đặt nó ở giữa như poster gốc đã làm, nó sẽ không hoạt động chính xác vì các tệp được cắt sẽ được in ngay lập tức và mệnh đề thứ hai sẽ không có cơ hội chọn các tệp mà nó muốn:

find . \( -type d -name aa -prune -o -print \) -o \( -type f -name 'file*' \)
.
./file1
./bb
./bb/file3

Thật không may, người đăng ban đầu đã nhận lệnh sai ở trên bằng cách đặt -printsai vị trí. Nó có thể đã làm việc cho trường hợp cụ thể của anh ta, nhưng nó không hoạt động trong trường hợp chung.

Có hàng ngàn người gặp khó khăn trong việc hiểu cách làm -pruneviệc. Các findtrang người đàn ông cần được cập nhật để ngăn chặn sự nhầm lẫn trên toàn thế giới Neverending về lệnh này.


Trang người đàn ông của tôi (Arch Linux, find-4.6.0) nói: "Nếu toàn bộ biểu thức không chứa hành động nào ngoài -prune hoặc -print, -print được thực hiện trên tất cả các tệp mà toàn bộ biểu thức là đúng." Nhưng hoạt động như bạn mô tả.
x-yuri

0

từ mantrang,

Để bỏ qua toàn bộ cây thư mục, hãy sử dụng -prune thay vì kiểm tra mọi tệp trong cây. Ví dụ, để bỏ qua thư mục `src / emacs 'và tất cả các tệp và thư mục bên dưới nó, và in tên của các tệp khác được tìm thấy, hãy làm như thế này:

find . -path ./src/emacs -prune -o -print

Vì vậy, có thể bạn có thể sử dụng:

find . -path ./.git -prune -o -print

Điều này sẽ không liệt kê các .gitthư mục.

để cụ thể một tên tệp, bạn có thể làm như thế này:

find . -path ./.git -prune , -name filename

Xin lưu ý ,toán tử dấu phẩy.


-1

Đây là một thay thế nhanh chóng và bẩn thỉu:

find | fgrep -v /.git

Tôi chỉ đơn giản là không thể nhớ findcú pháp phức tạ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.