Làm thế nào để liệt kê danh sách các tệp được trả về bằng lệnh find để cat để xem tất cả các tệp


204

Tôi đang làm một findvà sau đó nhận được một danh sách các tập tin. Làm thế nào để tôi chuyển nó sang một tiện ích khác như cat(để con mèo hiển thị nội dung của tất cả các tệp đó) và về cơ bản cần grepmột cái gì đó từ các tệp này.

Câu trả lời:


340
  1. Chuyển sang quy trình khác (Mặc dù điều này sẽ không hoàn thành những gì bạn nói bạn đang cố gắng thực hiện):

    command1 | command2
    

    Điều này sẽ gửi đầu ra của lệnh1 là đầu vào của lệnh2

  2. -exectrên một find(điều này sẽ làm những gì bạn muốn làm - nhưng cụ thể là find)

    find . -name '*.foo' -exec cat {} \;
    

    (Tất cả mọi thứ giữa find-execlà các biến vị ngữ tìm kiếm mà bạn đã sử dụng. {}Sẽ thay thế tệp cụ thể mà bạn tìm thấy trong lệnh ( cat {}trong trường hợp này); \;là kết thúc -execlệnh.)

  3. gửi đầu ra của một tiến trình dưới dạng đối số dòng lệnh đến tiến trình khác

    command2 `command1`
    

    ví dụ:

    cat `find . -name '*.foo' -print`
    

    (Lưu ý đây là BACK-QUOTES không phải là trích dẫn thông thường (dưới dấu ngã ~ trên bàn phím của tôi).) Điều này sẽ gửi đầu ra command1thành các command2đối số dòng lệnh. Lưu ý rằng tên tệp chứa khoảng trắng (dòng mới, v.v.) sẽ được chia thành các đối số riêng biệt.


2
con mèo find -name '*.foo' -printđã làm việc rất tốt cho tôi ... Cảm ơn
Devang Kamdar

Các backquote hoạt động rất tốt và khái quát hơn, bạn có thể sử dụng điều này để tạo danh sách các tệp từ một tệp.
Hazok

11
Lưu ý rằng các phiên bản hiện đại findcho phép bạn viết : find . -name '*.foo' -exec cat {} +, trong đó +chỉ ra rằng findnên nhóm nhiều tên tệp thuận tiện thành một lệnh gọi duy nhất. Điều này khá hữu ích (nó xử lý các khoảng trắng vv trong tên tệp mà không cần dùng đến -print0xargs -0).
Jonathan Leffler

18
Unmentioned:find . -name '*.foo' | xargs cat
stewSquared 24/8/2016

3
Chỉ cần thêm vào câu trả lời của @stewSquared: Để tìm tất cả các dòng trong các tệp có chứa một chuỗi nhất định, hãy làmfind . -name '*.foo' | xargs cat | grep string
Bim

84

Phiên bản hiện đại

POSIX 2008 đã thêm +điểm đánh dấu vào findđó có nghĩa là nó tự động nhóm nhiều tệp hợp lý thành một lệnh thực thi, rất giống như xargsvậy, nhưng với một số lợi thế:

  1. Bạn không phải lo lắng về các ký tự kỳ lạ trong tên tệp.
  2. Bạn không phải lo lắng về lệnh được gọi với tên tệp bằng không.

Vấn đề tên tệp là vấn đề xargskhông có -0tùy chọn và vấn đề 'chạy ngay cả với tên tệp không' là vấn đề có hoặc không có -0tùy chọn - nhưng GNU xargs-rhoặc --no-run-if-emptytùy chọn để ngăn điều đó xảy ra. Ngoài ra, ký hiệu này cắt giảm số lượng quy trình, không phải là bạn có khả năng đo lường sự khác biệt về hiệu suất. Do đó, bạn có thể viết một cách hợp lý:

find . -exec grep something {} +

Phiên bản cổ điển

find . -print | xargs grep something

Nếu bạn đang dùng Linux hoặc có GNU findxargscác lệnh, thì hãy sử dụng -print0vớifind-0với xargsđể xử lý các tên tệp có chứa khoảng trắng và các ký tự bóng lẻ khác.

find . -print0 | xargs -0 grep something

Tinh chỉnh kết quả từ grep

Nếu bạn không muốn tên tệp (chỉ là văn bản) thì hãy thêm một tùy chọn thích hợp vào grep(thường là -hđể loại bỏ 'tiêu đề'). Để đảm bảo tuyệt đối tên tệp được in bởi grep(ngay cả khi chỉ tìm thấy một tệp hoặc lệnh gọi cuối cùng grepchỉ được cung cấp 1 tên tệp), sau đó thêm /dev/nullvào xargsdòng lệnh, để luôn có ít nhất hai tên tệp.


Đối với những người bối rối như tôi, lưu ý rằng cách này trước tiên sẽ cung cấp cho tất cả đầu ra của tìm kiếm, và sau đó đưa ra đầu ra của xargs grep something.
Eric Hu

3
@EricHu: Tôi có thể thấy bạn đang bối rối, nhưng nó không làm những gì bạn nói, ít nhất là không phải trên bất kỳ hệ thống dựa trên Unix nào tôi biết. Đầu ra của findđược dẫn đến đầu vào tiêu chuẩn của xargs. Các xargschương trình đọc đầu vào tiêu chuẩn của nó, tách đầu vào lúc khoảng trắng (khoảng trống, dòng mới, các tab, vv) và gắn thêm một số các từ với lệnh grep somethingvà thực thi dòng lệnh. xargssau đó tiếp tục đọc các lệnh đầu vào và thực thi cho đến khi hết đầu vào. xargschạy greplệnh thường xuyên khi cần thiết cho đầu vào được đưa ra (từ findtrong ví dụ này).
Jonathan Leffler

Lỗi của tôi, đây là sử dụng grep để tìm kiếm trong mỗi tệp phù hợp. Tôi đang tìm cách đơn giản để lọc đầu ra của tìm kiếm với grep
Eric Hu

1
Lỗi chuyển sang lỗi tiêu chuẩn (mô tả tệp 2) trên tất cả các lệnh được xử lý tốt. Chuyển hướng stderr để /dev/nullmất các thông báo lỗi.
Jonathan Leffler

1
Điều này cũng có lợi ích là nó hoạt động tốt hơn với khoảng trắng trong đường dẫn tệp. Ngay cả 'sed'ing "" -> "\" cũng phá vỡ nó bằng `nhưng với xargs, nó hoạt động hoàn hảo
JZL003

36

Có một số cách để chuyển danh sách các tệp được findlệnh trả về cho catlệnh, mặc dù về mặt kỹ thuật không phải tất cả đều sử dụng đường ống và không có đường dẫn nào thực sự dẫn trực tiếp đến cat.

  1. Đơn giản nhất là sử dụng backticks ( `):

    cat `find [whatever]`
    

    Điều này nhận đầu ra findvà đặt nó một cách hiệu quả trên dòng lệnh của cat. Điều này không hoạt động tốt nếu findcó quá nhiều đầu ra (nhiều hơn có thể vừa với một dòng lệnh) hoặc nếu đầu ra có các ký tự đặc biệt (như khoảng trắng).

  2. Trong một số shell, bao gồm bash, người ta có thể sử dụng $()thay vì backticks:

    cat $(find [whatever])
    

    Điều này là ít di động, nhưng là lồng nhau. Bên cạnh đó, nó có khá nhiều cảnh báo tương tự như backticks.

  3. Bởi vì chạy các lệnh khác trên những gì được tìm thấy là sử dụng phổ biến cho find, find có một -exechành động thực thi một lệnh cho mỗi tệp mà nó tìm thấy:

    find [whatever] -exec cat {} \;
    

    Đây {}là một trình giữ chỗ cho tên tệp và \;đánh dấu sự kết thúc của lệnh (Có thể có các hành động khác sau -exec.)

    Điều này sẽ chạy catmột lần cho mỗi tệp duy nhất thay vì chạy một trường hợp cattruyền cho nó nhiều tên tệp có thể không hiệu quả và có thể không có hành vi bạn muốn cho một số lệnh (mặc dù điều đó tốt cat). Cú pháp cũng khó gõ - bạn cần thoát dấu chấm phẩy vì dấu chấm phẩy đặc biệt đối với shell!

  4. Một số phiên bản find(đáng chú ý nhất là phiên bản GNU) cho phép bạn thay thế ;bằng +để sử dụng -execchế độ chắp thêm để chạy ít phiên bản cat:

    find [whatever] -exec cat {} +
    

    Điều này sẽ chuyển nhiều tên tệp cho mỗi lần gọi cat, có thể hiệu quả hơn.

    Lưu ý rằng điều này không được đảm bảo để sử dụng một lệnh gọi, tuy nhiên. Nếu dòng lệnh sẽ quá dài thì các đối số được trải rộng trên nhiều lệnh cat. Đối với catđiều này có lẽ không phải là một vấn đề lớn, nhưng đối với một số lệnh khác, điều này có thể thay đổi hành vi theo những cách không mong muốn. Trên các hệ thống Linux, giới hạn độ dài dòng lệnh là khá lớn, do đó việc chia thành nhiều lệnh gọi là khá hiếm so với một số HĐH khác.

  5. Phương pháp cổ điển / di động là sử dụng xargs:

    find [whatever] | xargs cat
    

    xargschạy lệnh được chỉ định ( cat, trong trường hợp này) và thêm các đối số dựa trên những gì nó đọc từ stdin. Cũng giống như -execvới +, điều này sẽ phá vỡ dòng lệnh nếu cần thiết. Đó là, nếu findtạo ra quá nhiều đầu ra, nó sẽ chạy catnhiều lần. Như đã đề cập trong phần về -exectrước đó, có một số lệnh trong đó việc chia tách này có thể dẫn đến hành vi khác nhau. Lưu ý rằng việc sử dụng xargsnhư thế này có vấn đề với khoảng trắng trong tên tệp, vì xargschỉ sử dụng khoảng trắng làm dấu phân cách.

  6. Phương pháp mạnh mẽ, di động và hiệu quả nhất cũng sử dụng xargs:

    find [whatever] -print0 | xargs -0 cat
    

    Các -print0lá cờ nói findđể sử dụng \0(null ký tự) delimiters giữa tên tập tin, và các -0lá cờ nói xargsđể mong đợi những \0dấu phân cách. Điều này có khá nhiều hành vi giống hệt với -exec... +cách tiếp cận, mặc dù có tính di động cao hơn (nhưng không may là dài dòng hơn).


Phương thức backtick là tuyệt vời, vì nó cũng hoạt động cho các lệnh khác ls.
Martin Braun

@Martin Braun sử dụng $()Cũng hoạt động với các lệnh khác find .
Laurence Gonsalves

Cảm ơn, rất tốt để biết, tôi đã ngừng đọc sau (1), vì nó phục vụ nhu cầu của tôi, vì tôi không xử lý các ký tự đặc biệt như khoảng trắng và như vậy.
Martin Braun

9

Để đạt được điều này (sử dụng bash) tôi sẽ làm như sau:

cat $(find . -name '*.foo')

Điều này được gọi là "thay thế lệnh" và nó loại bỏ nguồn cấp dữ liệu theo mặc định là thực sự thuận tiện!

thêm thông tin ở đây


6

Nghe có vẻ như một công việc cho một kịch bản shell đối với tôi:

for file in 'find -name *.xml'
do
   grep 'hello' file
done

hoặc điều tương tự


2
Đây là một câu trả lời hợp lệ, mặc dù không nhất thiết là tối ưu.
Jonathan Leffler

1
... Vâng nhưng thật tuyệt nếu bạn muốn có một tệp lớn với tên tệp được liệt kê.
ʍǝɥʇɐɯ

1
Tôi thích điều này nhất. Một khối vòng lặp như thế này rời khỏi phòng để làm những việc khác.
kakyo

4

Đây là cách của tôi để tìm tên tệp có chứa một số nội dung mà tôi quan tâm, chỉ là một dòng bash duy nhất xử lý các khoảng trắng trong tên tệp:

find . -name \*.xml | while read i; do grep '<?xml' "$i" >/dev/null; [ $? == 0 ] && echo $i; done

3

Tôi sử dụng một cái gì đó như thế này:

find . -name <filename> -print0 | xargs -0 cat | grep <word2search4>

" -print0" Lập luận cho "tìm" và " -0" lập luận cho "xargs" là cần thiết để xử lý khoảng trắng trong tập tin đường dẫn / tên một cách chính xác.



2

Đây là ảnh của tôi để sử dụng chung:

grep YOURSTRING `find .`

Nó sẽ in tên tập tin


2

Trong bash, những điều sau đây sẽ phù hợp:

find /dir -type f -print0 | xargs -0i cat {} | grep whatever

Điều này sẽ tìm thấy tất cả các tập tin trong /dirthư mục, và đưa tên tập tin vào xargsmột cách an toàn grep.

Bỏ qua xargskhông phải là một ý tưởng tốt nếu bạn có nhiều ngàn tệp trong đó /dir; catsẽ phá vỡ do độ dài danh sách đối số quá mức. xargssẽ sắp xếp tất cả ra cho bạn

Đối -print0số để chia findlưới với -0đối số xargsđể xử lý tên tệp có khoảng trắng đúng. Đối -isố xargscho phép bạn chèn tên tệp khi cần trong catdòng lệnh. Các dấu ngoặc được thay thế bằng tên tệp được dẫn vào catlệnh từ find.


0

Điều này làm việc cho tôi

find _CACHE_* | while read line; do
    cat "$line" | grep "something"
done

0

Sử dụng ggrep .

ggrep -H -R -I "mysearchstring" *

để tìm kiếm một tệp trong unix chứa văn bản nằm trong thư mục hiện tại hoặc thư mục con


0

Điều này sẽ in tên và nội dung của các tệp chỉ đệ quy ..

find . -type f -printf '\n\n%p:\n' -exec cat {} \;

Chỉnh sửa (Phiên bản cải tiến): Điều này sẽ in tên và nội dung của tệp văn bản (ascii) chỉ đệ quy ..

find . -type f -exec grep -Iq . {} \; -print | xargs awk 'FNR==1{print FILENAME ":" $0; }'

Thêm một lần thử

find . -type f -exec grep -Iq . {} \; -printf "\n%p:" -exec cat {} \;

-1

Bạn đang cố gắng tìm văn bản trong các tập tin? Bạn chỉ có thể sử dụng grep cho ...

grep searchterm *

-1

Để liệt kê và xem nội dung của tất cả các tệp abc.def trên máy chủ trong thư mục / ghi và / jkl

find /ghi /jkl -type f -name abc.def 2> /dev/null -exec ls {} \; -exec cat {} \;

Để liệt kê các tệp abc.def có các mục nhận xét và hiển thị, hãy xem các mục đó trong thư mục / ghi và / jkl

find /ghi /jkl -type f -name abc.def 2> /dev/null -exec grep -H ^# {} \;
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.