Tìm tất cả các tập tin không phải là nhị phân


43

Có thể sử dụng findlệnh để tìm tất cả các tệp "không nhị phân" trong một thư mục không? Đây là vấn đề tôi đang cố gắng giải quyết.

Tôi đã nhận được một kho lưu trữ các tập tin từ một người dùng windows. Kho lưu trữ này chứa mã nguồn và tập tin hình ảnh. Hệ thống xây dựng của chúng tôi không chơi tốt với các tệp có kết thúc dòng windows. Tôi có một chương trình dòng lệnh ( flip -u) sẽ lật các kết thúc dòng giữa * nix và windows. Vì vậy, tôi muốn làm một cái gì đó như thế này

find . -type f | xargs flip -u

Tuy nhiên, nếu lệnh này được chạy với tệp hình ảnh hoặc tệp phương tiện nhị phân khác, nó sẽ làm hỏng tệp. Tôi nhận ra rằng tôi có thể xây dựng một danh sách các phần mở rộng tệp và bộ lọc với điều đó, nhưng tôi muốn có một cái gì đó không phụ thuộc vào tôi để giữ cho danh sách đó được cập nhật.

Vì vậy, có cách nào để tìm tất cả các tệp không nhị phân trong cây thư mục không? Hoặc có một giải pháp thay thế tôi nên xem xét?


1
Bạn có thể sử dụng filetiện ích ở đâu đó trong tập lệnh / đường ống của mình để xác định xem tệp là dữ liệu hay văn bản
lk-

1
Bạn có ý nghĩa gì bởi phi nhị phân (mọi thứ trên máy tính hiện đại là nhị phân). Tôi đoán bạn đang sử dụng sự khác biệt từ hệ điều hành C / PM cũ, có tệp văn bản và tệp nhị phân. Các tệp văn bản có thể có độ dài bất kỳ nhưng phải kết thúc bằng ctrl-z và các tệp nhị phân phải là bội số của một khối 512byte. Nếu vậy bạn có nghĩa là tập tin văn bản. (Tôi cũng lưu ý rằng bạn viết về dòng kết thúc trong tệp không nhị phân, điều này cũng sẽ gợi ý rằng chúng là tệp văn bản) Điều này có đúng không?
ctrl-alt-delor

Tất cả các tập tin là nhị phân, nó chỉ là một vấn đề giải thích. Bạn đang hỏi làm thế nào để tìm tập tin văn bản?
ctrl-alt-delor

@richard Tôi hình thành một kỷ nguyên mà chúng ta gọi các tệp có nghĩa là được hiểu là văn bản thuần văn bản thuần túy và tất cả các tệp khác (hình ảnh, tài liệu xử lý văn bản, v.v.) nhị phân. Tôi biết tất cả chỉ là một và số không dưới mui xe :)
Alan Storm

1
À, tôi hiểu ý của bạn về các điều khoản của tôi - tôi sẽ sử dụng nhị phân / văn bản trong tương lai để tránh nhầm lẫn. Re: điều \ r \ n - tôi hiểu đó là các ký tự ASCII cho sự trở lại vận chuyển của máy đánh chữ (di chuyển đến đầu dòng) và nguồn cấp dữ liệu (di chuyển xuống một dòng). Vì vậy, \ r \ n là một mô hình "chính xác hơn" về vật lý trong thế giới thực mà một nhân vật cuối dòng dành cho. Trước OS X, máy Mac chỉ sử dụng \ r cho việc này. Tôi thường viết toàn bộ điều này là "những lựa chọn tùy tiện được đưa ra một cách vội vàng mà chúng ta vẫn đang giải quyết"
Alan Storm

Câu trả lời:


20

Tôi sẽ sử dụng filevà chuyển đầu ra thành grep hoặc awk để tìm tệp văn bản, sau đó trích xuất chỉ phần tên tệp của fileđầu ra và đường ống thành xargs.

cái gì đó như:

file * | awk -F: '/ASCII text/ {print $1}' | xargs -d'\n' -r flip -u

Lưu ý rằng grep tìm kiếm 'văn bản ASCII' chứ không phải bất kỳ 'văn bản' nào - bạn có thể không muốn gây rối với các tài liệu Rich Text hoặc các tệp văn bản unicode, v.v.

Bạn cũng có thể sử dụng find(hoặc bất cứ điều gì) để tạo danh sách các tệp cần kiểm tra với file:

find /path/to/files -type f -exec file {} + | \
  awk -F: '/ASCII text/ {print $1}' | xargs -d'\n' -r flip -u

Đối -d'\n'số cho xargs làm cho xargs coi mỗi dòng đầu vào là một đối số riêng biệt, do đó phục vụ cho tên tệp có khoảng trắng và các ký tự có vấn đề khác. tức là nó là một thay thế cho xargs -0khi nguồn đầu vào không hoặc không thể tạo ra NULL-tách ra (ví dụ như find's -print0tùy chọn). Theo changelog, xargs có tùy chọn -d/ --delimitervào tháng 9 năm 2005 nên có trong bất kỳ bản phân phối linux không cổ nào (tôi không chắc chắn, đó là lý do tại sao tôi đã kiểm tra - tôi chỉ nhớ một cách mơ hồ rằng đó là một bổ sung "gần đây").

Lưu ý rằng một nguồn cấp dữ liệu là một ký tự hợp lệ trong tên tệp, vì vậy điều này sẽ bị phá vỡ nếu bất kỳ tên tệp nào có nguồn cấp dữ liệu trong đó. Đối với người dùng unix điển hình, điều này là điên rồ về mặt bệnh lý, nhưng không phải là chưa từng thấy nếu các tệp có nguồn gốc trên máy Mac hoặc Windows.

Cũng lưu ý rằng filekhông hoàn hảo. Rất tốt trong việc phát hiện loại dữ liệu trong một tệp nhưng đôi khi có thể bị nhầm lẫn.

Tôi đã sử dụng nhiều biến thể của phương pháp này nhiều lần trong quá khứ với thành công.


1
Cảm ơn giải pháp này! Vì một số lý do filehiển thị English textthay vì ASCII texttrên hệ thống Solaris của tôi, vì vậy tôi đã sửa đổi phần đó cho phù hợp. Ngoài ra, tôi thay thế awk -F: '{print $1}'bằng tương đương cut -f1 -d:.
Andrew Cheong

3
grep -Ibộ lọc nhị phân đáng nói
xenoterracide

Tìm từ textnên là đủ. Điều này cũng sẽ nhận các filemô tả như ASCII Java program texthoặc HTML document texthoặc troff or preprocessor input text.
dùng1024

Câu trả lời của tôi một phần là một phản ứng / cải thiện cho câu trả lời này. Điểm rất tốt về grepping ASCII textđể tránh làm hỏng RTF.
tự đại diện

1
xenoterracide: Bạn đã cứu người đàn ông của tôi! Chỉ là một lá cờ -I và BINGO
Sergio Abreu

9

Không có gì đặc biệt về tệp nhị phân hoặc không nhị phân. Bạn có thể sử dụng phương pháp phỏng đoán như 'chỉ chứa các ký tự trong 0x01 Mạnh0x7F', nhưng điều đó sẽ gọi các tệp văn bản với các tệp nhị phân không phải ký tự ASCII và các tệp văn bản tệp nhị phân không may mắn.

Bây giờ, một khi bạn đã bỏ qua rằng ...

tập tin zip

Nếu nó đến từ người dùng Windows của bạn dưới dạng tệp zip, định dạng zip hỗ trợ đánh dấu các tệp dưới dạng nhị phân hoặc văn bản trong chính kho lưu trữ. Bạn có thể sử dụng -atùy chọn giải nén để chú ý đến điều này và chuyển đổi. Tất nhiên, xem đoạn đầu tiên để biết lý do tại sao điều này có thể không phải là một ý tưởng tốt (chương trình zip có thể đã đoán sai khi nó thực hiện lưu trữ).

zipinfo sẽ cho bạn biết tập tin nào là nhị phân (b) hoặc văn bản (t) trong danh sách zipfile của nó.

những tập tin khác

Lệnh tập tin sẽ xem xét một tập tin và cố gắng xác định nó. Cụ thể, có thể bạn sẽ thấy -itùy chọn (loại MIME đầu ra) của nó hữu ích; chỉ chuyển đổi tập tin với loại văn bản / *


6

Một giải pháp chung để chỉ xử lý các tệp không nhị phân khi bashsử dụng file -b --mime-encoding:

while IFS= read -d '' -r file; do
  [[ "$(file -b --mime-encoding "$file")" = binary ]] &&
    { echo "Skipping   $file."; continue; }

  echo "Processing $file."

  # ...

done < <(find . -type f -print0)

Tôi đã liên hệ với tác giả của tiện ích tệp và anh ta đã thêm một tham số tiện lợi -00trong phiên bản 5.26 (phát hành 2016-04-16, ví dụ như trong Arch và Ubuntu 16.10 hiện tại) in ra file\0result\0nhiều tệp được cung cấp cho nó cùng một lúc, bằng cách này bạn có thể làm ví dụ:

find . -type f -exec file -00 --mime-encoding {} + |
  awk 'BEGIN{ORS=RS="\0"}{if(NR%2)f=$0;else if(!/binary/)print f}' | 

(Phần awknày là để lọc ra mọi tệp không phải là nhị phân. ORSLà dấu tách đầu ra.)

Cũng có thể được sử dụng trong một vòng lặp của khóa học:

while IFS= read -d '' -r file; do

  echo "Processing $file."

  # ...

done < <(find . -type f -exec file -00 --mime-encoding {} + |
  awk 'BEGIN{ORS=RS="\0"}{if(NR%2)f=$0;else if(!/binary/)print f}')

Dựa trên điều này và trước đó tôi đã tạo ra một bashtập lệnh nhỏ để lọc các tệp nhị phân sử dụng phương thức mới bằng cách sử dụng -00tham số filetrong các phiên bản mới hơn của nó và quay lại phương thức trước đó trên các phiên bản cũ hơn:

#!/bin/bash

# Expects files as arguments and returns the ones that do
# not appear to be binary files as a zero-separated list.
#
# USAGE:
#   filter_binary_files.sh [FILES...]
#
# EXAMPLE:
#   find . -type f -mtime +5 -exec ./filter_binary_files.sh {} + | xargs -0 ...
# 

[[ $# -eq 0 ]] && exit

if [[ "$(file -v)" =~ file-([1-9][0-9]|[6-9]|5\.([3-9][0-9]|2[6-9])) ]]; then
  file -00 --mime-encoding -- "$@" |
    awk 'BEGIN{ORS=RS="\0"}{if(NR%2)f=$0;else if(!/binary/)print f}'
else
  for f do
    [[ "$(file -b --mime-encoding -- "$f")" != binary ]] &&
      printf '%s\0' "$f"
  done
fi

Hoặc ở đây một POSIX-y hơn, nhưng nó yêu cầu hỗ trợ cho sort -V:

#!/bin/sh

# Expects files as arguments and returns the ones that do
# not appear to be binary files as a zero-separated list.
#
# USAGE:
#   filter_binary_files.sh [FILES...]
#
# EXAMPLE:
#   find . -type f -mtime +5 -exec ./filter_binary_files.sh {} + | xargs -0 ...
# 

[ $# -eq 0 ] && exit

if [ "$(printf '%s\n' 'file-5.26' "$(file -v | head -1)" | sort -V)" = \
    'file-5.26' ]; then
  file -00 --mime-encoding -- "$@" |
    awk 'BEGIN{ORS=RS="\0"}{if(NR%2)f=$0;else if(!/binary/)print f}'
else
  for f do
    [ "$(file -b --mime-encoding -- "$f")" != binary ] &&
      printf '%s\0' "$f"
  done
fi

6

Câu trả lời được chấp nhận đã không tìm thấy tất cả chúng cho tôi. Dưới đây là một ví dụ sử dụng grep's -Iđể bỏ qua các tệp nhị phân và bỏ qua tất cả các tệp ẩn ...

find . -type f -not -path '*/\.*' -exec grep -Il '.' {} \; | xargs -L 1 echo 

Ở đây nó được sử dụng trong một ứng dụng thực tế: dos2unix

https://unix.stackexchange.com/a/365679/112190


4

Câu trả lời của Cas là tốt, nhưng nó giả sử tên tập tin lành mạnh ; đặc biệt người ta cho rằng tên tệp sẽ không chứa dòng mới.

Không có lý do chính đáng nào để đưa ra giả định này ở đây, vì theo tôi thì khá đơn giản (và thực sự sạch hơn) để xử lý trường hợp đó một cách chính xác:

find . -type f -exec sh -c 'file "$1" | grep -q "ASCII text"' sh {} \; -exec flip -u {} \;

Các findlệnh chỉ tận dụng các tính năng POSIX chỉ định . Sử dụng -execđể chạy các lệnh tùy ý như các bài kiểm tra boolean rất đơn giản, mạnh mẽ (xử lý tên tệp lẻ chính xác) và dễ mang theo hơn -print0.

Trong thực tế, tất cả các phần của lệnh được chỉ định bởi POSIX ngoại trừ flip.

Lưu ý rằng filekhông đảm bảo tính chính xác của kết quả mà nó trả về. Tuy nhiên, trong thực tế grepping cho "văn bản ASCII" trong đầu ra của nó là khá đáng tin cậy.

(Nó có thể bỏ lỡ tập tin một số văn bản có lẽ, nhưng là rất rất khó có thể xác định sai một tập tin nhị phân là "văn bản ASCII" và mangle nó-vì vậy chúng tôi đang erring về phía thận trọng.)


Tệp không callscó đối số có thể khá chậm, ví dụ: đối với video, nó sẽ cho bạn biết mọi thứ về mã hóa.
phk

Ngoài ra, bạn đang giả sử không có tập tin bắt đầu với -.
phk

Và tôi thấy không có lý do tại sao bạn sẽ không thực hiện một cuộc gọi đến file, nó có thể lấy nhiều tệp làm đối số.
phk

@phk, để giải quyết ý kiến ​​của bạn: (1) thật tốt khi biết sự chậm chạp tiềm năng, nhưng tôi thấy không có cách nào POSIX để ngăn chặn điều đó; (2) Tôi đưa ra các giả định bằng không về tên tệp, vì findlệnh sẽ tiền tố ./cho bất kỳ tên tệp nào được truyền cho lệnh shell; (3) Sử dụng greplàm thử nghiệm trên một fileđầu ra lệnh duy nhất tại một thời điểm là cách POSIX duy nhất tôi có thể thấy để đảm bảo xử lý chính xác tên tệp có thể chứa dòng mới.
tự đại diện

Tôi đã xem qua giải pháp "POSIX-y" cuối cùng của bạn và tôi nghĩ rằng đó là thông minh, nhưng bạn cho rằng filehỗ trợ --mime-encodingcờ và --dải phân cách, cả hai đều không được POSIX đảm bảo .
tự đại diện

2
find . -type f -exec grep -I -q . {} \; -print

Điều này sẽ tìm thấy tất cả các tệp thông thường ( -type f) trong thư mục hiện tại (hoặc bên dưới) cho greprằng không trống và không nhị phân.

Nó sử dụng grep -Iđể phân biệt giữa các tệp nhị phân và không nhị phân. Các -Ilá cờ và sẽ gây ra grepđể thoát với một trạng thái thoát khác không khi nó phát hiện rằng một tập tin là nhị phân. Theo một tệp "nhị phân" grep, một tệp chứa ký tự nằm ngoài phạm vi ASCII có thể in được.

Các -qtùy chọn để grepsẽ gây ra nó để bỏ thuốc lá với một tình trạng không lối ra nếu mô hình cụ thể được tìm thấy, mà không phát ra bất kỳ dữ liệu. Mẫu mà chúng tôi sử dụng là một dấu chấm đơn, sẽ phù hợp với bất kỳ ký tự nào.

Nếu tệp được tìm thấy là không nhị phân và nếu nó chứa ít nhất một ký tự, tên của tệp được in.

Nếu bạn cảm thấy dũng cảm, bạn cũng có thể cắm flip -uvào đó:

find . -type f -exec grep -I -q . {} \; -print -exec flip -u {} \;

1

Thử đi :

find . -type f -print0 | xargs -0 -r grep -Z -L -U '[^         -~]' | xargs -0 -r flip -u

Trường hợp đối số grep '[^ -~]''[^<tab><space>-~]'.

Nếu bạn gõ nó trên một dòng lệnh shell, gõ Ctrl+ Vtrước Tab. Trong một trình soạn thảo, sẽ không có vấn đề gì.

  • '[^<tab><space>-~]'sẽ khớp với bất kỳ ký tự nào không phải là văn bản ASCII (trả về vận chuyển bị bỏ qua bởi grep).
  • -L sẽ chỉ in tên tệp của các tệp không khớp
  • -Zsẽ xuất tên tệp được phân tách bằng ký tự null (for xargs -0)

Điều đáng chú ý là với Regex giống Perl grep -P(nếu có) \tcó sẵn. Ngoài ra, sử dụng bản dịch ngôn ngữ nếu shell hỗ trợ nó: $'\t'( bashzshlàm).
phk

1

Giải pháp thay thế:

Lệnh dos2unix sẽ chuyển đổi các kết thúc dòng từ Windows CRLF sang Unix LF và tự động bỏ qua các tệp nhị phân. Tôi áp dụng đệ quy bằng cách sử dụng:

find . -type f -exec dos2unix {} \;

dos2unixcó thể lấy nhiều tên tệp làm đối số, nên sẽ hiệu quả hơn nhiềufind . -type f -exec dos2unix {} +
Anthon

0

sudo find / (-type f -and -path '* / git / *' -iname 'README') -exec grep -liI '100644 \ | 100755' {} \; -exec lật -u {} \;

i. (-type f -and -path '* / git / *' -iname 'README'): tìm kiếm các tệp trong một đường dẫn chứa tên git và tệp có tên README. Nếu bạn biết bất kỳ thư mục cụ thể và tên tệp để tìm kiếm nó sẽ hữu ích.

Lệnh ii.-exec chạy một lệnh trên tên tệp được tạo bởi find

iii. \; chỉ ra kết thúc lệnh

iv. {} là đầu ra của tệp / tên người dùng được tìm thấy từ tìm kiếm tìm trước đó

Các lệnh v.Multipl có thể được chạy sau đó. Bằng cách nối thêm -exec "lệnh" \; chẳng hạn như với -exec lật -u \;

vii.grep

1.-l lists the name of the file
2.-I searches only non-binary files
3.-q quiet output
4.'100644\|100755' searches for either 100644 or 100755 within the file found. if found it then runs flip -u. \| is the or operator for grep. 

bạn có thể sao chép thư mục kiểm tra này và dùng thử: https://github.com/alphaCTzo7G/stackexchange/tree/master/linux/findSolution204092017

câu trả lời chi tiết hơn tại đây: https://github.com/alphaCTzo7G/stackexchange/blob/master/linux/findSolution204092017/README.md

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.