it-mot-dan-vi.com

Điều gì làm cho grep coi một tập tin là nhị phân?

Tôi có một số cơ sở dữ liệu từ hệ thống Windows trên hộp của mình. Chúng là các tệp văn bản. Tôi đang sử dụng cygwin để grep qua chúng. Chúng dường như là các tệp văn bản đơn giản; Tôi mở chúng bằng các trình soạn thảo văn bản như notepad và wordpad và chúng trông dễ đọc. Tuy nhiên, khi tôi chạy grep trên chúng, nó sẽ báo binary file foo.txt matches.

Tôi đã nhận thấy rằng các tệp chứa một số ký tự ascii NUL, mà tôi tin là các tạo phẩm từ kết xuất cơ sở dữ liệu.

Vậy điều gì khiến grep coi những tập tin này là nhị phân? Ký tự NUL? Có một cờ trên hệ thống tập tin? Tôi cần thay đổi gì để có được grep để hiển thị cho tôi các kết quả khớp dòng?

203
user394

Nếu có ký tự NUL ở bất kỳ đâu trong tệp, grep sẽ coi đó là tệp nhị phân.

Có thể có một cách giải quyết như thế này cat file | tr -d '\000' | yourgrep để loại bỏ tất cả null trước, sau đó tìm kiếm qua tệp.

139
bbaja42

grep -a đã làm cho tôi:

$ grep --help
[...]
 -a, --text                equivalent to --binary-files=text
140
Plouff

Bạn có thể sử dụng tiện ích strings để trích xuất nội dung văn bản từ bất kỳ tệp nào và sau đó chuyển nó qua grep, như thế này: strings file | grep pattern.

21
holgero

GNU grep 2.24 RTFS

Kết luận: chỉ 2 và 2 trường hợp:

  • NUL, ví dụ: printf 'a\0' | grep 'a'

  • lỗi mã hóa theo C99 mbrlen(), ví dụ:

    export LC_CTYPE='en_US.UTF-8'
    printf 'a\x80' | grep 'a'
    

    bởi vì \x80 không thể là byte đầu tiên của điểm Unicode UTF-8: TF-8 - Mô tả | en.wikipedia.org

Hơn nữa, như được đề cập bởi Stéphane Chazelas Điều gì khiến grep coi một tệp là nhị phân? | Unix & Linux Stack Exchange , những kiểm tra đó chỉ được thực hiện cho đến lần đọc bộ đệm đầu tiên có độ dài TODO.

Chỉ tối đa bộ đệm đầu tiên đọc

Vì vậy, nếu một lỗi NUL hoặc mã hóa xảy ra ở giữa một tệp rất lớn, thì nó có thể bị lỗi.

Tôi tưởng tượng điều này là vì lý do hiệu suất.

Ví dụ: điều này in dòng:

printf '%10000000s\n\x80a' | grep 'a'

nhưng điều này không:

printf '%10s\n\x80a' | grep 'a'

Kích thước bộ đệm thực tế phụ thuộc vào cách đọc tệp. Ví dụ. đối chiếu:

export LC_CTYPE='en_US.UTF-8'
(printf '\n\x80a') | grep 'a'
(printf '\n'; sleep 1; printf '\x80a') | grep 'a'

Với sleep, dòng đầu tiên được chuyển đến grep ngay cả khi nó chỉ dài 1 byte vì quá trình chuyển sang chế độ ngủ và lần đọc thứ hai không kiểm tra xem tệp có phải là nhị phân hay không.

[~ # ~] rtfs [~ # ~]

git clone git://git.savannah.gnu.org/grep.git 
cd grep
git checkout v2.24

Tìm nơi thông báo lỗi stderr được mã hóa:

git grep 'Binary file'

Dẫn chúng tôi đến /src/grep.c:

if (!out_quiet && (encoding_error_output
                    || (0 <= nlines_first_null && nlines_first_null < nlines)))
    {
    printf (_("Binary file %s matches\n"), filename);

Nếu các biến đó được đặt tên tốt, về cơ bản chúng tôi đã đi đến kết luận.

mã hóa_errorDefput

Grepping nhanh cho encoding_error_output Cho thấy rằng đường dẫn mã duy nhất có thể sửa đổi nó đi qua buf_has_encoding_errors:

clen = mbrlen (p, buf + size - p, &mbs);
if ((size_t) -2 <= clen)
  return true;

sau đó chỉ cần man mbrlen.

nlines_first_null và nlines

Khởi tạo là:

intmax_t nlines_first_null = -1;
nlines = 0;

vì vậy khi null được tìm thấy 0 <= nlines_first_null trở thành đúng.

TODO khi nào nlines_first_null < nlines Có thể sai? Tôi đã lười biếng.

[~ # ~] posix [~ # ~]

Không xác định tùy chọn nhị phân grep - tìm kiếm tệp cho mẫu | pubs.opengroup.org và GNU grep không ghi lại tài liệu đó, vì vậy RTFS là cách duy nhất .

Một trong những tệp văn bản của tôi đột nhiên bị grep xem là nhị phân:

$ file foo.txt
foo.txt: ISO-8859 text

Giải pháp là chuyển đổi nó bằng cách sử dụng iconv:

iconv -t UTF-8 -f ISO-8859-1 foo.txt > foo_new.txt
6
zzapper

Tập tin /etc/magic hoặc là /usr/share/misc/magic có một danh sách các chuỗi mà lệnh file sử dụng để xác định loại tệp.

Lưu ý rằng nhị phân có thể chỉ là một giải pháp dự phòng. Đôi khi các tập tin với mã hóa lạ cũng được coi là nhị phân.

grep trên Linux có một số tùy chọn để xử lý các tệp nhị phân như --binary-files hoặc là -U / --binary

5
klapaucius

Trên thực tế trả lời câu hỏi "Điều gì khiến grep coi một tệp là nhị phân?", Bạn có thể sử dụng iconv:

$ iconv < myfile.Java
iconv: (stdin):267:70: cannot convert

Trong trường hợp của tôi, có các ký tự tiếng Tây Ban Nha xuất hiện chính xác trong các trình soạn thảo văn bản nhưng grep coi chúng là nhị phân; iconv đầu ra chỉ cho tôi số dòng và số cột của các ký tự đó

Trong trường hợp NUL ký tự, iconv sẽ coi chúng là bình thường và sẽ không in loại đầu ra đó nên phương pháp này không phù hợp

2
golimar

Một trong những học sinh của tôi đã có vấn đề này. Có một lỗi trong grep in Cygwin. Nếu tệp có các ký tự không phải là chữ Asii, grepegrep xem nó là nhị phân.

2
Joan Pontius

Tôi đã từng gặp vấn đề tương tự. Tôi đã sử dụng vi -b [filename] để xem các ký tự được thêm vào. Tôi tìm thấy các ký tự điều khiển ^@^M. Sau đó, trong vi loại :1,$s/^@//g để xóa ^@ nhân vật. Lặp lại lệnh này cho ^M.

Cảnh báo: Để có được các ký tự điều khiển "màu xanh", nhấn Ctrl+v sau đó Ctrl+M hoặc là Ctrl+@. Sau đó lưu và thoát vi.

1
Not Sure