grep이 파일을 이진 파일로 간주하는 이유는 무엇입니까?


185

상자에 Windows 시스템에서 일부 데이터베이스 덤프가 있습니다. 텍스트 파일입니다. cygwin을 사용하여 grep하고 있습니다. 이들은 일반 텍스트 파일 인 것 같습니다. 메모장 및 워드 패드와 같은 텍스트 편집기로 파일을 열고 읽을 수있게 보입니다. 그러나 grep을 실행하면라고 말합니다 binary file foo.txt matches.

파일에 일부 ASCII NUL문자가 포함되어 있으며 데이터베이스 덤프의 아티팩트라고 생각합니다.

grep이이 파일들을 바이너리로 간주하게 만드는 것은 무엇입니까? NUL문자? 파일 시스템에 플래그가 있습니까? grep이 줄 일치를 표시하도록하려면 무엇을 변경해야합니까?


2
--null-dataNUL구분 기호 인 경우 유용 할 수 있습니다 .
Steve-o

답변:


125

NUL파일 어딘가에 문자 가 있으면 , grep은이를 2 진 파일로 간주합니다.

이러한 방법으로 cat file | tr -d '\000' | yourgrep모든 null을 먼저 제거한 다음 파일을 검색 할 수 있습니다.


149
... 또는 GNU grep과 함께 -a/를 사용하십시오 --text.
derobert

1
@derobert : 실제로 일부 (더 오래된) 시스템에서는 grep이 행을 보지만 출력은 처음에 각 일치하는 행을 자릅니다 NUL(아마도 C의 printf를 호출하고 일치하는 행을 제공하기 때문일까요?). grep cmd .sh_historysh_history NUL의 각 줄은 각 줄의 시작 부분에 특정 형식을 가지기 때문에 그러한 시스템에서 a 는 'cmd'와 일치하는 줄만큼 많은 빈 줄을 반환 합니다. (. 그러나 당신의 코멘트는 "적어도 GNU의 그렙에"아마 내가 테스트 지금 손이없는 진정한 온다, 그러나 나는 그들이이 잘 처리 할 것으로 예상)
올리비에 Dulac

4
NUL 캐릭터의 존재가 유일한 기준입니까? 나는 그것을 의심한다. 아마도 그보다 똑똑 할 것입니다. Ascii 32-126 범위를 벗어나는 것은 내 추측 일 것입니다.하지만 소스 코드를 확인해야합니다.
Michael Martinez

2
내 정보는 특정 grep 인스턴스의 맨 페이지에서 가져온 것입니다. 구현에 대한 귀하의 의견은 유효합니다.
bbaja42

2
grepcygwin에서 이진 파일 로 일반 ASCII 하이픈 / 빼기 (0x2d) 대신 긴 대시 (0x96)가 있기 때문에 바이너리를 고려한 파일이 있습니다. 이 답변이 OP의 문제를 해결했다고 생각하지만 불완전한 것으로 보입니다.
cp.engr

121

grep -a 나를 위해 일했다 :

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

4
이것은 가장 저렴하고 저렴한 IMO 답변입니다.
pydsigner

POSIX 호환
Matteo

21

당신이 사용할 수있는 strings텍스트의 모든 파일의 내용 다음 파이프를 통해 추출 유틸리티를 grep이 등을 : strings file | grep pattern.


2
부분적으로 손상되었을 수있는 로그 파일을 잡는 데 이상적
Hannes R.

예, 때때로 이진 혼합 로깅도 발생합니다. 이거 좋다
sdkks

13

GNU grep 2.24 RTFS

결론 : 2와 2의 경우 만 :

  • NUL예를 들어 printf 'a\0' | grep 'a'

  • C99에 따른 인코딩 오류 mbrlen(), 예 :

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

    때문에 \x80UTF-8 유니 포인트의 첫 번째 바이트가 될 수 없습니다 : UTF-8 - 설명 | en.wikipedia.org

또한 Stéphane Chazelas가 언급했듯이 grep이 파일을 이진 파일로 간주하게 만드는 이유는 무엇입니까? | 유닉스 및 리눅스 스택 교환에서 , 이러한 검사는 TODO 길이의 첫 번째 버퍼 읽기까지만 수행됩니다.

첫 번째 버퍼 읽기까지만

따라서 매우 큰 파일 중간에 NUL 또는 인코딩 오류가 발생하면 어쨌든 잘릴 수 있습니다.

이것이 성능상의 이유라고 생각합니다.

예 : 줄을 인쇄합니다 :

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

그러나 이것은하지 않습니다 :

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

실제 버퍼 크기는 파일을 읽는 방법에 따라 다릅니다. 예 : 비교 :

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

을 사용하면 sleep프로세스가 잠자기 때문에 첫 번째 행이 1 바이트 길이 인 경우에도 grep에 전달되고 두 번째 읽기는 파일이 이진인지 확인하지 않습니다.

RTFS

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

stderr 오류 메시지가 인코딩 된 위치를 찾으십시오.

git grep 'Binary file'

우리를 이끌어줍니다 /src/grep.c:

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

이러한 변수의 이름이 잘 정해지면 기본적으로 결론에 도달했습니다.

encoding_error_output

빠른 grepping for encoding_error_output는 그것을 수정할 수있는 유일한 코드 경로가 통과한다는 것을 보여줍니다 buf_has_encoding_errors.

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

그럼 그냥 man mbrlen.

nlines_first_null 및 nlines

다음과 같이 초기화 됨 :

intmax_t nlines_first_null = -1;
nlines = 0;

따라서 null이 발견 0 <= nlines_first_null되면 true가됩니다.

TODO는 nlines_first_null < nlines언제 거짓 일 수 있습니까? 게으르다

POSIX

바이너리 옵션 grep을 정의하지 않음 -패턴을 찾기 위해 파일 검색 | pubs.opengroup.org 및 GNU grep 은이를 문서화하지 않으므로 RTFS가 유일한 방법입니다.


1
인상적인 설명!
user394

2
유효한 UTF-8 검사는 UTF-8 로케일에서만 발생합니다. 또한 검사는 파일에서 읽은 첫 번째 버퍼에서만 수행됩니다. 일반 파일의 경우 시스템의 32768 바이트 인 것처럼 보이지만 파이프 또는 소켓의 경우 1 바이트만큼 작을 수 있습니다. 비교 (printf '\n\0y') | grep y(printf '\n'; sleep 1; printf '\0y') | grep y예를 들어.
Stéphane Chazelas

@ StéphaneChazelas "유효한 UTF-8 검사는 UTF-8 로케일에서만 발생합니다.": export LC_CTYPE='en_US.UTF-8'예 에서 와 같은 것을 의미 합니까? Buf 읽기 : 놀라운 예가 대답에 추가되었습니다. 당신은 분명 그 생각 나게, 나보다 소스 더 읽고 해커 화두 "학생이었다 계몽":-)를
치로 틸리新疆改造中心法轮功六四事件


1
@CiroSantilli 巴拿馬 文件 六四 事件 法轮功 어떤 GNU grep 버전을 테스트 했습니까?
jrw32982

6

내 텍스트 파일 중 하나가 grep에 의해 갑자기 바이너리로 표시되었습니다.

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

해결책은 다음을 사용하여 변환하는 것입니다 iconv.

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

1
이것은 나에게도 일어났다. 특히, 원인은 ISO-8859-1- 인코딩 된 비 분리 공간으로, 파일에서 grep을 검색하기 위해 일반 공간으로 교체해야했습니다.
Gallaecio

4
grep 2.21은 ISO-8859 텍스트 파일을 이진 파일로 취급하므로 grep 명령 전에 export LC_ALL = C를 추가하십시오.
netawater

@netawater 감사합니다! 예를 들어 텍스트 파일에 Müller와 같은 것이있는 경우입니다. 그건 0xFC범위 GREP은 UTF8에 대한 (최대 예상 외부 그래서 16 진수 0x7F). printf 'a \ x7F'로 확인하십시오 | Ciro가 위에서 설명한 것처럼 grep 'a'.
앤 반 로섬

5

파일 /etc/magic또는 /usr/share/misc/magic명령 file이 파일 유형을 결정하는 데 사용 하는 시퀀스 목록이 있습니다.

참고 바이너리 그냥 대체 솔루션이 될 수 있습니다. 때때로 이상한 인코딩을 가진 파일도 이진으로 간주됩니다.

grepLinux에는 --binary-files또는 같은 이진 파일을 처리하는 몇 가지 옵션이 있습니다.-U / --binary


보다 정확하게는 C99에 따른 인코딩 오류 mbrlen()입니다. 의 예와 소스 해석 : unix.stackexchange.com/a/276028/32558
치로 틸리新疆改造中心法轮功六四事件

2

내 학생 중 한 명이이 문제를 겪었습니다. 에 버그가 grep있습니다 Cygwin. 파일이 ASCII가 아닌 문자를 가지고있는 경우 grepegrep진로를 참조하십시오.


그것은 버그가 아닌 기능처럼 들립니다. 특히 그것을 제어 할 수있는 명령 줄 옵션이 있습니다 (-a / --text)
Will Sheppard

2

실제로 "grep가 파일을 이진 파일로 간주하게 만드는 이유"라는 질문에 대답하면 다음을 사용할 수 있습니다 iconv.

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

필자의 경우 텍스트 편집기에서 올바르게 표시되는 스페인어 문자가 있었지만 grep은 해당 문자를 이진으로 간주했습니다. iconv출력은 그 문자의 줄과 열 번호를 가리 켰습니다.

NUL문자 의 경우 , iconv정상으로 간주하고 해당 종류의 출력을 인쇄하지 않으므로이 방법은 적합하지 않습니다


1

나는 같은 문제가 있었다. 내가 사용하는 vi -b [filename]추가 문자를 볼 수 있습니다. 제어 문자 ^@및을 찾았습니다 ^M. 그런 다음 vi를 입력 :1,$s/^@//g하여 ^@문자 를 제거하십시오 . 에 대해이 명령을 반복하십시오 ^M.

경고 : "파란색"제어 문자를 얻으려면 Ctrl+를 v누른 다음 Ctrl+ M또는 Ctrl+를 누르십시오 @. 그런 다음 vi를 저장하고 종료하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.