Tôi đang làm một find
và 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 grep
một cái gì đó từ các tệp này.
Tôi đang làm một find
và 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 grep
một cái gì đó từ các tệp này.
Câu trả lời:
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
-exec
trê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
và -exec
là 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 -exec
lệnh.)
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 command1
thà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.
find
cho phép bạn viết : find . -name '*.foo' -exec cat {} +
, trong đó +
chỉ ra rằng find
nê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 -print0
và xargs -0
).
find . -name '*.foo' | xargs cat
find . -name '*.foo' | xargs cat | grep string
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ư xargs
vậy, nhưng với một số lợi thế:
Vấn đề tên tệp là vấn đề xargs
không có -0
tù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ó -0
tùy chọn - nhưng GNU xargs
có -r
hoặc --no-run-if-empty
tù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 {} +
find . -print | xargs grep something
Nếu bạn đang dùng Linux hoặc có GNU find
và xargs
các lệnh, thì hãy sử dụng -print0
vớifind
và -0
vớ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
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 grep
chỉ được cung cấp 1 tên tệp), sau đó thêm /dev/null
vào xargs
dòng lệnh, để luôn có ít nhất hai tên tệp.
xargs grep something
.
find
được dẫn đến đầu vào tiêu chuẩn của xargs
. Các xargs
chươ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 something
và thực thi dòng lệnh. xargs
sau đó tiếp tục đọc các lệnh đầu vào và thực thi cho đến khi hết đầu vào. xargs
chạy grep
lệnh thường xuyên khi cần thiết cho đầu vào được đưa ra (từ find
trong ví dụ này).
/dev/null
mất các thông báo lỗi.
Có một số cách để chuyển danh sách các tệp được find
lệnh trả về cho cat
lệ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
.
Đơn giản nhất là sử dụng backticks ( `
):
cat `find [whatever]`
Điều này nhận đầu ra find
và đặ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 find
có 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).
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.
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 -exec
hà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 cat
một lần cho mỗi tệp duy nhất thay vì chạy một trường hợp cat
truyề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!
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 -exec
chế độ 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.
Phương pháp cổ điển / di động là sử dụng xargs
:
find [whatever] | xargs cat
xargs
chạ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ư -exec
với +
, điều này sẽ phá vỡ dòng lệnh nếu cần thiết. Đó là, nếu find
tạo ra quá nhiều đầu ra, nó sẽ chạy cat
nhiều lần. Như đã đề cập trong phần về -exec
trướ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 xargs
như thế này có vấn đề với khoảng trắng trong tên tệp, vì xargs
chỉ sử dụng khoảng trắng làm dấu phân cách.
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 -print0
lá cờ nói find
để sử dụng \0
(null ký tự) delimiters giữa tên tập tin, và các -0
lá cờ nói xargs
để mong đợi những \0
dấ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).
ls
.
$()
Cũng hoạt động với các lệnh khác find
.
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ự
Lệnh find có một đối số -exec mà bạn có thể sử dụng cho những thứ như thế này, bạn chỉ có thể thực hiện grep trực tiếp bằng cách sử dụng.
Ví dụ ( từ đây, các ví dụ hay khác tại trang này ):
find . -exec grep "www.athabasca" '{}' \; -print
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 /dir
thư mục, và đưa tên tập tin vào xargs
một cách an toàn grep
.
Bỏ qua xargs
không phải là một ý tưởng tốt nếu bạn có nhiều ngàn tệp trong đó /dir
; cat
sẽ phá vỡ do độ dài danh sách đối số quá mức. xargs
sẽ sắp xếp tất cả ra cho bạn
Đối -print0
số để chia find
lưới với -0
đối số xargs
để xử lý tên tệp có khoảng trắng đúng. Đối -i
số xargs
cho phép bạn chèn tên tệp khi cần trong cat
dòng lệnh. Các dấu ngoặc được thay thế bằng tên tệp được dẫn vào cat
lệnh từ find
.
Điều này làm việc cho tôi
find _CACHE_* | while read line; do
cat "$line" | grep "something"
done
Đ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 {} \;
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 *
Để 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 ^# {} \;
find -name '*.foo' -print
đã làm việc rất tốt cho tôi ... Cảm ơn