Làm cách nào tôi có thể gửi nội dung của các tệp được tìm thấy bằng cách sử dụng find vào một tệp?


11

Tôi đã xoay sở để tự bắn vào nơi đau đớn (thực sự tồi tệ) bằng cách định dạng lại một phân vùng chứa dữ liệu có giá trị. Tất nhiên đó không phải là cố ý, nhưng nó đã xảy ra.

Tuy nhiên, tôi đã quản lý để sử dụng testdiskphotoreckhôi phục hầu hết dữ liệu. Vì vậy, bây giờ tôi có tất cả dữ liệu được phân phối trên gần 25.000 thư mục. Hầu hết các tệp là tệp .txt, còn lại là tệp hình ảnh. Có hơn 300 tệp .txt trong mỗi thư mục.

Tôi có thể grephoặc sử dụng findđể trích xuất một số chuỗi nhất định từ các tệp .txt và xuất chúng thành một tệp. Ví dụ: đây là một dòng mà tôi đã sử dụng để xác minh rằng dữ liệu của tôi nằm trong các tệp được khôi phục:

find ./recup*/ -name '*.txt' -print | xargs grep -i "searchPattern"

Tôi có thể xuất "searchPotype" thành một tệp, nhưng điều đó chỉ mang lại cho tôi mẫu đó. Đây là những gì tôi thực sự muốn thực hiện:

Đi qua tất cả các tập tin và tìm kiếm một chuỗi cụ thể. Nếu chuỗi đó được tìm thấy trong một tệp, hãy gửi TẤT CẢ nội dung của tệp đó vào một tệp đầu ra. Nếu mẫu được tìm thấy trong nhiều tệp, nối thêm nội dung của các tệp tiếp theo vào tệp đầu ra đó. Lưu ý rằng tôi chỉ không muốn xuất mẫu mà tôi đang tìm kiếm, nhưng TẤT CẢ nội dung của tệp trong đó các mẫu được tìm thấy.

Tôi nghĩ điều này là có thể thực hiện được, nhưng tôi chỉ không biết cách lấy tất cả nội dung của một tập tin sau khi lấy một mẫu cụ thể từ nó.


Vì vậy, với lệnh bạn cung cấp, nó cung cấp cho bạn kết quả mà bạn đang tìm kiếm nhưng bạn đang tìm cách chuyển hướng đầu ra sang một tệp văn bản?
ryekayo

Sau khi đọc câu hỏi của tôi, đoạn đó bắt đầu bằng "Đi qua ..." nghe giống như psuedocode. Có lẽ tôi có thể lấy mã bằng một vài dòng cho / nếu mã Python. Sẽ cho nó một shot trong khi tôi chờ phản hồi có nhiều thông tin hơn
Ami

Nó chắc chắn là psuedocode, và tôi chắc chắn bạn cũng có thể tìm ra cách để làm điều đó trong bash.
ryekayo

@ryekayo, Có, nó mang lại cho tôi đầu ra, nhưng đó chỉ là để tìm tập tin cụ thể của loại dữ liệu nào trong đó, cho tôi biết rằng có nhiều dữ liệu hơn trong tệp đó. Vì vậy, tôi muốn lấy tất cả mọi thứ trong tập tin đó và ghi chúng vào tập tin khác.
Ami

Bạn có thể có thể gói lệnh đó trong một số loại câu lệnh if hoặc thậm chí là một trường hợp chuyển đổi có thể gọi một hàm có thể loại bỏ nội dung dựa trên trường hợp hoặc kết quả của câu lệnh if
ryekayo

Câu trả lời:


10

Nếu tôi hiểu chính xác mục tiêu của bạn, những điều sau đây sẽ làm những gì bạn muốn:

find ./recup*/ -name '*.txt' -exec grep -qi "searchPattern" {} \; -exec cat {} \; > outputfile.txt

Điều này sẽ tìm kiếm tất cả *.txtcác tệp trong ./recup*/, kiểm tra từng tệp cho searchPattern, nếu nó phù hợp với nó sẽ catlà tệp. Đầu ra của tất cả catcác tập tin ed sẽ được hướng vào outputfile.txt.

Lặp lại cho mỗi mẫu và tập tin đầu ra.


Nếu bạn có một số lượng lớn các thư mục phù hợp ./recup*, bạn có thể kết thúc bằng một argument list too long error. Thay vào đó, cách đơn giản là làm một cái gì đó như thế này:

find ./ -mindepth 2 -path './recup*.txt' -exec grep -qi "searchPattern" {} \; -exec cat {} \; > outputfile.txt

Điều này sẽ phù hợp với đường dẫn đầy đủ. Vì vậy, ./recup01234/foo/bar.txtsẽ được kết hợp. Các -mindepth 2là để nó sẽ không phù hợp ./recup.txt, hoặc ./recup0.txt.


Vâng, tôi nghĩ rằng sẽ làm điều đó. Và nó cho tôi một cơ sở để làm việc. Vì tôi sẽ tìm kiếm nhiều chuỗi, tôi nghĩ rằng một mã for / if, với nhiều elif sẽ giúp tôi tự động hóa tác vụ. Cảm ơn bạn
Ami

Điều đó thậm chí còn tốt hơn những gì tôi đã nghĩ lol
ryekayo

Điều đó dường như không hoạt động. Đã gặp lỗi này: "không thể thực thi / usr / bin / find: Danh sách đối số quá dài"
Ami

@Ami cập nhật câu trả lời để cung cấp giải pháp cho vấn đề đó.
Patrick

2
@Ami Nếu bạn đang sử dụng nhiều chuỗi, có thể đơn giản hơn là chỉ lưu tất cả các tên tệp tích cực vào một tệp khác ( grep -l), sau đó |sort|uniqcattừ danh sách tệp.
Sparhawk

3

Thay vì xuất ra mẫu của bạn, hãy xuất tên tệp bằng cách sử dụng "-l" trên grep, sau đó sử dụng mẫu đó làm đầu vào cho cat.

find ./recup*/ -name '*.txt' -print | xargs grep -li "searchPattern" | xargs cat

hoặc là

cat $( find ./recup*/ -name '*.txt' -print | xargs grep -li "searchPattern")

Tôi nghi ngờ rằng bạn có thể điền vào các chi tiết còn lại. BTW, nếu bạn có thể có khoảng trắng hoặc các ký tự lẻ khác trong tên tệp (không có khả năng trong trường hợp cụ thể này, nhưng cho mục đích trong tương lai), hãy sử dụng -print0 trên find và -Z trên grep, kết hợp với tùy chọn -0 trên xargs để sử dụng null byte giữa tên tệp thay vì dòng mới.

find ./recup*/ -name '*.txt' -print0 | xargs -0 grep -Zli "searchPattern" | xargs -0 cat

2
Tôi cũng thích tùy chọn "hai -exec" của Patrick, ngoại trừ việc nó sẽ gây ra một ngã ba mới (tốt, clone ()) và thực thi cho mọi tệp. Thông thường bạn có thể sử dụng \+thay vì \;để tránh vấn đề đó, nhưng tôi không biết làm thế nào nó hoạt động với một cặp đối số -exec (tôi nghi ngờ "kém"). Sử dụng một cặp xargs, bạn sẽ chỉ có một vài quy trình mới được sinh ra, sẽ nhanh hơn với nhiều tệp.
dannysauer

Điều này có vẻ tốt, quá. Cảm ơn. Một câu hỏi không có thật: Con mèo sau lần xarg cuối cùng sẽ xuất ra một tập tin, phải không?
Ami

Khi tôi lần đầu tiên đọc nó, tôi đã không nghĩ câu hỏi được chỉ định nơi nội dung của tệp sẽ đi. Cả ba các lệnh đặt nội dung file (s) trên STDOUT, vì vậy bạn chỉ muốn append (cho đến cuối cùng) >afilehoặc |acommandhoặc bất cứ điều gì là thích hợp cho tình hình của bạn. :)
dannysauer

Câu trả lời hay, tôi cần cho mèo pg_hba.conf sudo find /* -name pg_hba.conf | xargs sudo cat
Ứng dụng vào

Đây là một chủ đề nhỏ, nhưng tôi thích sử dụng sudo xargsthay vì xargs sudo. Khi bạn chạy xargs sudo, nó xây dựng dòng lệnh giả sử lệnh là sudo cat args. Nhưng con mèo ở trong / bin, nên sudo chạy /bin/cat args. Nếu lệnh của bạn nằm trong một thư mục dài hơn, như / usr / local / bin, thì lệnh sudo thực sự chạy có thể dẫn đến một dòng lệnh quá dài và một lỗi khó theo dõi. Trên hết, sudo xargschỉ ghi nhật ký rằng bạn đã chạy xargs, trong khi xargs sudoghi nhật ký lệnh với tất cả các đối số - dẫn đến một số dòng nhật ký sudo dài. :)
dannysauer

1

Đây không phải là mã chính xác tối ưu, nhưng nó rất đơn giản và sẽ hoạt động tốt nếu hiệu quả không phải là vấn đề. Vấn đề là nó sẽ grep qua các tệp nhiều lần, ngay cả khi chuỗi đã được tìm thấy trong chúng.

Đầu tiên, tìm kiếm các chuỗi của bạn và viết các tệp phù hợp vào một danh sách.

find ./recup*/ -name '*.txt' -execdir grep -il "searchPattern" {} >> /tmp/file_list \;

Lặp lại bước này thay thế searchPatternkhi cần thiết. Điều này tạo ra một danh sách các tập tin phù hợp tại /tmp/file_list.

Vấn đề là tập tin này có thể có các bản sao trong đó. Do đó, chúng ta có thể thay thế các bản sao bằng |sort|uniq. Phần sortđặt các bản sao liền kề nhau, để uniqcó thể loại bỏ chúng. Sau đó, bạn có thể catsử dụng các tệp này cùng nhau xargs(với mỗi tên tệp được phân tách bằng dòng mới \n). Vì thế,

</tmp/file_list sort | uniq | xargs -d "\n" cat > final_file.txt

Không giống như các câu trả lời khác, điều này có hai bước trong đó và một tệp tạm thời, vì vậy tôi thực sự chỉ đề xuất nó nếu bạn có nhiều mẫu để tìm.


0

Tùy thuộc vào vỏ và môi trường của bạn, bạn có thể có một cái gì đó như thế này (trong bash)

while IFS= read -r -d '' file; do
  if grep -qim1 'searchPattern1\|searchPattern2\|searchPattern3' "$file"; then
    cat "$file" >> some/other/file
  fi
done < <(find ./recup*/ -name '*.txt' -print0)

Nếu bạn muốn tách kết quả theo mẫu, bạn có thể sửa đổi nó thành một cái gì đó như

while IFS= read -r -d '' file; do
  if grep -qim1 'searchPattern1' "$file"; then
    cat "$file" >> some/other/file1
  elif grep -qim1 'searchPattern2' "$file"; then
    cat "$file" >> some/other/file2
  elif grep -qim1 'searchPattern3' "$file"; then
    cat "$file" >> some/other/file3
  fi
done < <(find ./recup*/ -name '*.txt' -print0)

Các bit sau khi "thực hiện" làm gì? Điều tôi thực sự thích là sửa đổi nếu khối đó sao cho các tệp chứa mẫu phù hợp được ghi vào một tệp khác.
Ami

Nó chỉ liệt kê các tệp '.txt' được tìm thấy, mỗi tệp được chấm dứt bởi ký tự null (để nó an toàn cho tên tệp chứa khoảng trắng và các ký tự khác). Các whilevòng lặp sau đó đọc danh sách đó và hiện grep/ có điều kiện catphần.
Steeldo

Khi tôi cố chạy mã, tôi gặp lỗi này: ./recoverData.sh: Lỗi cú pháp: "(" không mong muốn. Điều đó xuất phát từ dấu ngoặc quanh lệnh find
Ami

Bạn đang sử dụng vỏ gì? cú pháp thay thế quy trình là dành riêng cho bash - do đó trình độ chuyên môn của tôi "Tùy thuộc vào vỏ và môi trường của bạn"
Steeldo

1
Bạn có thể thực thi (các) lệnh trực tiếp trong shell bash tương tác hoặc đặt chúng vào một tệp có dòng đầu tiên chứa shebang #!/bin/bash, làm cho nó có thể thực thi được chmod +x recoverData.shvà thực hiện bằng cách sử dụng ./recoverData.sh. Đừng không sử dụng sh recoverData.shkể từ khi /bin/shcó thể là một dashvỏ .
Steeldo
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.