Làm thế nào để tôi bao gồm một đường ống | trong lệnh linux của tôi tìm -exec?


220

Điều này không hiệu quả. Điều này có thể được thực hiện trong tìm kiếm? Hay tôi cần xargs?

find -name 'file_*' -follow -type f -exec zcat {} \| agrep -dEOE 'grep' \;

Câu trả lời:


145

Công việc diễn giải biểu tượng đường ống như một hướng dẫn để chạy nhiều quy trình và đưa đầu ra của một quy trình vào đầu vào của một quy trình khác là trách nhiệm của trình bao (/ bin / sh hoặc tương đương).

Trong ví dụ của bạn, bạn có thể chọn sử dụng trình bao cấp cao nhất của mình để thực hiện đường ống như vậy:

find -name 'file_*' -follow -type f -exec zcat {} \; | agrep -dEOE 'grep'

Về mặt hiệu quả, kết quả này tiêu tốn một lần tìm kiếm, nhiều lần gọi zcat và một lần gọi agrep.

Điều này sẽ chỉ dẫn đến một quá trình agrep duy nhất được sinh ra, nó sẽ xử lý tất cả đầu ra được tạo ra bởi nhiều yêu cầu của zcat.

Nếu bạn vì lý do nào đó muốn gọi agrep nhiều lần, bạn có thể làm:

find . -name 'file_*' -follow -type f \
    -printf "zcat %p | agrep -dEOE 'grep'\n" | sh

Điều này xây dựng một danh sách các lệnh sử dụng các đường ống để thực thi, sau đó gửi chúng đến một vỏ mới để thực sự được thực thi. (Bỏ qua "| sh" cuối cùng là một cách hay để gỡ lỗi hoặc thực hiện các dòng lệnh khô như thế này.)

Về mặt hiệu quả, kết quả này tiêu tốn một lần tìm kiếm, một lần gọi sh, nhiều lần gọi zcat và nhiều lần gọi agrep.

Giải pháp hiệu quả nhất về số lượng các lệnh truyền lệnh là gợi ý từ Paul Tomblin:

find . -name "file_*" -follow -type f -print0 | xargs -0 zcat | agrep -dEOE 'grep'

... Chi phí cho một lần gọi tìm kiếm, một lần gọi xargs, một vài lần gọi zcat và một lần gọi agrep.


1
Một ưu điểm khác của xargs là, bạn có thể tăng tốc nó với cpu đa lõi hiện đại hơn nữa, bằng cách sử dụng công tắc -P (-P 0).
flolo

Vâng, swich -P thực sự là một cách hay để tăng tốc độ thực thi nói chung. Thật không may, bạn có nguy cơ đầu ra của các quá trình zcat song song được dẫn vào agrep xen kẽ, điều này sẽ ảnh hưởng đến kết quả. Hiệu ứng này có thể được chứng minh bằng cách sử dụng: echo -e "1 \ n2" | xargs -P 0 -n 1 có | uniq
Rolf W. Rasmussen

@Adam, tôi đã thực hiện thay đổi đề xuất của bạn.
Paul Tomblin

mà bạn có thể cài đặt lệnh xjobs lộng lẫy (ban đầu từ Solaris)
sehe

4
Một câu trả lời đơn giản và tổng quát hơn là tại stackoverflow.com/a/21825690/42973 : -exec sh -c "… | … " \;.
Eric O Lebigot

278

giải pháp rất dễ dàng: thực hiện thông qua sh

... -exec sh -c "zcat {} | agrep -dEOE 'grep' " \;

17
Những gì OP đã cố gắng thực hiện có thể được đáp ứng với các đề xuất ở trên, nhưng đây là câu trả lời thực sự cho câu hỏi. Có nhiều lý do để làm theo cách này - exec mạnh hơn rất nhiều so với việc chỉ hoạt động trên các tệp được trả về bởi find, đặc biệt là khi kết hợp với kiểm tra. Ví dụ: tìm geda-gaf / -type d -exec bash -c 'DIR = {}; [[$ (tìm $ DIR -maxdepth 1 | xargs grep -i spice | wc -l) -ge 5]] && echo $ DIR '\; Sẽ trả về tất cả các thư mục trong đường dẫn tìm kiếm chứa tổng cộng hơn 5 dòng trong số tất cả các tệp trong thư mục đó chứa từ gia vị
swarfrat

3
Câu trả lời tốt nhất. Cắt xén toàn bộ đầu ra (như các câu trả lời khác gợi ý) không giống với grep mỗi tệp. Mẹo: thay vì sh, bạn có thể sử dụng bất kỳ shell nào khác mà bạn muốn (Tôi đã thử điều đó với bash và nó chạy ổn).
pagliuca

1
Hãy chắc chắn để không bỏ qua các -ctùy chọn. Nếu không, bạn sẽ nhận được một No such file or directorythông báo lỗi khó hiểu .
asmaier

đây là một thay thế ps tuyệt vời sử dụng tìm kiếm với đường ống bên trong lớp vỏ thực thi: / usr / bin / find / Proc -mindepth 1 -maxdepth 1 -type d -regex '. * / [0-9] +' - in -exec bash -c "cat {} / cmdline | tr '\\ 0' ''; echo" \;
chẵn lẻ3

1
Ví dụ về việc tìm tệp và đổi tên chúng bằng sed sử dụng biểu thức chính quy find -type f -name '*.mdds' -exec sh -c "echo {} | sed -e 's/_[0-9]\+//g' | xargs mv {}" \;
Rostfrei

16
find . -name "file_*" -follow -type f -print0 | xargs -0 zcat | agrep -dEOE 'grep'

Hy vọng để tránh -print và xargs vì lý do hiệu quả. Có lẽ đó là thực sự vấn đề của tôi: find không thể xử lý đường ống lệnh qua exec
someguy

Điều này không hoạt động với các tệp có khoảng trắng trong tên của chúng; để sửa chữa, thay thế -print bằng -print0 và thêm tùy chọn -0 vào xargs
Adam Rosenfield

2
@someguy - Cái gì? Tránh xargs vì lý do hiệu quả? Gọi một ví dụ của zcat, và đi qua nó một danh sách nhiều tập tin, là xa hiệu quả hơn exec-ing một trường hợp mới của nó cho mỗi tập tin được tìm thấy.
Sherm Pendley

@Adam - Tôi đã thực hiện thay đổi đề xuất của bạn. 99% thời gian khi tôi tìm thấy, nó nằm trong các thư mục mã nguồn của tôi và không có tệp nào trong đó có khoảng trắng nên tôi không bận tâm với print0. Bây giờ, thư mục tài liệu của tôi, mặt khác, tôi nhớ print0.
Paul Tomblin

10

Bạn cũng có thể dẫn đến một whilevòng lặp có thể thực hiện nhiều hành động trên tệp findđịnh vị. Vì vậy, đây là một cái để tìm trong jarkho lưu trữ cho một tệp lớp java đã cho trong thư mục với một bản phân phối lớn của jarcác tệp

find /usr/lib/eclipse/plugins -type f -name \*.jar | while read jar; do echo $jar; jar tf $jar | fgrep IObservableList ; done

điểm mấu chốt là whilevòng lặp chứa nhiều lệnh tham chiếu đến tên tệp được phân tách bằng dấu chấm phẩy và các lệnh này có thể bao gồm các đường ống. Vì vậy, trong ví dụ đó, tôi lặp lại tên của tệp phù hợp, sau đó liệt kê những gì trong bộ lọc lưu trữ cho một tên lớp đã cho. Đầu ra trông như sau:

/usr/lib/eclipse/plugins/org.eclipse.core.contenttype.source_3.4.1.R35x_v20090826-0451.jar /usr/lib/eclipse/plugins/org.eclipse.core.databinding.observable_1.2009090 .jar org / eclipse / core / databinding / obsable / list / IObservableList. class /usr/lib/eclipse/plugins/org.eclipse.search.source_3.5.1.r351_v20090708-0800.jar / usr / lib / eclipse / plugins org.eclipse.jdt.apt.core.source_3.3.202.R35x_v20091130-2300.jar /usr/lib/eclipse/plugins/org.eclipse.cvs.source_1.0.400.v201002111343.jar / usr / lib / eclipse org.eclipse.help.appserver_3.1.400.v20090429_1800.jar

trong shell bash của tôi (xubfox10.04 / xfce), nó thực sự làm cho tên lớp được khớp được in đậm làm fgrepnổi bật chuỗi khớp; điều này làm cho nó thực sự dễ dàng để quét xuống danh sách hàng trăm jartệp đã được tìm kiếm và dễ dàng xem bất kỳ trận đấu nào.

trên windows bạn có thể làm điều tương tự với:

for /R %j in (*.jar) do @echo %j & @jar tf %j | findstr IObservableList

lưu ý rằng trong các cửa sổ, dấu phân cách lệnh là '&' không ';' và rằng '@' triệt tiêu tiếng vang của lệnh để đưa ra một đầu ra gọn gàng giống như đầu ra tìm linux ở trên; mặc dù findstrkhông làm cho chuỗi phù hợp được in đậm nên bạn phải nhìn kỹ hơn một chút ở đầu ra để xem tên lớp phù hợp. Hóa ra lệnh 'for' của windows biết khá nhiều thủ thuật như lặp qua các tệp văn bản ...

thưởng thức


2

Tôi thấy rằng việc chạy lệnh shell shell (sh -c) hoạt động tốt nhất, ví dụ:

find -name 'file_*' -follow -type f -exec bash -c "zcat \"{}\" | agrep -dEOE 'grep'" \;

0

Nếu bạn đang tìm kiếm một giải pháp thay thế đơn giản, điều này có thể được thực hiện bằng cách sử dụng một vòng lặp:

for i in $(find -name 'file_*' -follow -type f);do zcat $i | agrep -dEOE 'grep');done

hoặc, hình thức tổng quát và dễ hiểu hơn:

for i in $(YOUR_FIND_COMMAND);do YOUR_EXEC_COMMAND_AND_PIPES );done

và thay thế bất kỳ {} bằng $ i trong YOU_EXEC_COMMAND_AND_PIPES

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.