박스에 Windows 시스템의 데이터베이스 덤프가 있습니다. 텍스트 파일입니다. 저는 cygwin을 사용하여 파일을 grep합니다.이 파일은 일반 텍스트 파일 인 것 같습니다. 메모장 및 워드 패드와 같은 텍스트 편집기로 파일을 열면 읽을 수 있습니다. 그러나 grep을 실행하면 binary file foo.txt matches
.
파일에 데이터베이스 덤프의 아티팩트라고 생각되는 일부 ascii NUL
문자가 포함되어 있습니다.
그러면 grep이이 파일을 바이너리로 간주하게 만드는 이유는 무엇입니까? NUL
문자입니까? 파일 시스템에 플래그가 있습니까? grep을 얻으려면 무엇을 변경해야합니까? 일치하는 줄을 표시 하시겠습니까?
댓글
답변
NUL
문자를 파일에 포함하면 grep은이를 바이너리 파일로 간주합니다.
이 cat file | tr -d "\000" | yourgrep
와 같은 해결 방법이있을 수 있습니다. 먼저 모두 null이고 그런 다음 파일을 검색합니다.
댓글
- … 또는
-a
/(적어도 GNU grep 포함)
- @derobert : 실제로 일부 (이전) 시스템에서는 grep이 줄을 보지만 출력은 처음에 일치하는 각 줄을 자릅니다.
NUL
(아마 C '의 printf를 호출하고 일치하는 줄을 제공하기 때문일까요?). 이러한 시스템에서grep cmd .sh_history
는 ' cmd ', sh_history의 각 줄에는 각 줄의 시작 부분에NUL
가있는 특정 형식이 있습니다. (하지만 " 적어도 GNU grep "에 대한 귀하의 의견은 아마도 사실 일 것입니다. 저는 그렇지 않습니다. ' 지금 당장 테스트 할 수있는 것은 없지만, 그들이 이것을 잘 처리 할 것으로 기대합니다) - NUL 문자의 존재가 유일한 기준입니까? 나는 그것을 의심한다. ' 아마도 그보다 더 똑똑 할 것입니다. Ascii 32-126 범위를 벗어나는 것은 내 추측이지만 ' 확실하게 소스 코드를 살펴 봐야합니다.
- 내 정보는 다음과 같습니다. 특정 grep 인스턴스의 man 페이지에서. 구현에 대한 귀하의 의견은 유효합니다. 소스는 문서보다 우선합니다.
- cygwin에서
grep
파일이 바이너리 대신에 긴 대시 (0x96)가 있기 때문에 바이너리로 간주되었습니다. 일반 ASCII 하이픈 / 빼기 (0x2d). 이 답변으로 OP ' 문제가 해결 된 것 같지만 불완전한 것으로 보입니다.
답변
grep -a
가 저에게 효과적이었습니다.
$ grep --help [...] -a, --text equivalent to --binary-files=text
댓글
- 이것은 가장 저렴하고 가장 저렴한 IMO 답변입니다.
- 그러나 POSIX를 준수하지 않습니다.
- 왜 그렇지 않은지 설명해 주시겠습니까? 이 답변을 선택 사항으로 찾는 우리 모두에게 분명히 해두면 좋을 것입니다. 감사합니다 :).
- 안녕하세요. '이 LOL을 다시 배우기 위해 두 번째로 여기에 왔습니다. 텍스트의 프랑스어 악센트 (분음 부호)로 인해 grep이 바프되었습니다
Answer
strings
유틸리티를 사용하여 파일에서 텍스트 콘텐츠를 추출한 다음 grep
를 통해 다음과 같이 파이프합니다. strings file | grep pattern
.
댓글
- 부분적으로 손상되었을 수있는 로그 파일을 검색하는 데 이상적입니다.
- 예, 때때로 바이너리 혼합 로깅 또한 발생합니다. 좋습니다.
답변
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"
\x80
는 UTF-8 유니 코드 포인트의 첫 번째 바이트가 될 수 없기 때문에 : UTF-8-설명 | en.wikipedia.org
또한 Stéphane Chazelas가 언급했듯이 grep이 파일로 간주하는 이유 바이너리입니까? | Unix & Linux Stack Exchange , 이러한 검사는 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);
이러한 변수의 이름이 적절하다면 기본적으로 결론에 도달했습니다.
p>
encoding_error_output
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가됩니다.
할 수있는 경우 nlines_first_null < nlines
거짓일까요? 게으르다.
POSIX
바이너리 옵션을 정의하지 않습니다. grep-파일에서 패턴 검색 | pubs.opengroup.org 이며 GNU grep은이를 문서화하지 않으므로 RTFS가 유일한 방법입니다.
댓글
- 인상적인 설명 !
- 유효한 UTF-8 확인은 UTF-8 로케일에서만 발생합니다. 또한 검사는 파일에서 읽은 첫 번째 버퍼에서만 수행되며 일반 파일의 경우 내 시스템에서 32768 바이트로 보이지만 파이프 또는 소켓의 경우 1 바이트만큼 작을 수 있습니다. 예를 들어
(printf '\n\0y') | grep y
를(printf '\n'; sleep 1; printf '\0y') | grep y
와 비교하세요. - @St é phaneChazelas " 유효한 UTF-8 확인은 UTF-8 로케일에서만 발생합니다. " :
또는 다른 무엇입니까? Buf 읽기 : 놀라운 예, 대답에 추가되었습니다. 당신은 분명히 저보다 소스를 더 많이 읽었고, 해커 코안 을 상기시켜줍니다. " 학생은 깨달았습니다. " 🙂
- '도 자세히 살펴 보지 않았지만 최근에
- @CiroSantilli 巴拿馬 文件 六四 事件 法轮功 어떤 버전의 GNU grep에 대해 테스트 했습니까?
답변
내 텍스트 파일 중 하나가 갑자기 grep에 의해 바이너리로 표시되었습니다.
$ file foo.txt foo.txt: ISO-8859 text
해결책은 iconv
를 사용하여 변환하는 것이 었습니다.
iconv -t UTF-8 -f ISO-8859-1 foo.txt > foo_new.txt
댓글
- 나도 마찬가지입니다. 특히 그 원인은 ISO-8859-1로 인코딩 된 non-breaking 공백이었는데, 파일에서 grep을 검색하려면 일반 공백으로 바꿔야했습니다.
- grep 2.21은 ISO를 처리합니다. -8859 텍스트 파일이 바이너리 인 것처럼, grep 명령 앞에 export LC_ALL = C를 추가합니다.
- @netawater 감사합니다! 이것은 예입니다. 텍스트 파일에 M ü ller와 같은 것이있는 경우입니다. 그 '의
0xFC
16 진수이므로 grep 범위 밖에서는 utf8 (최대0x7F
). printf로 확인 ' a \ x7F ' | Ciro가 위에서 설명한대로 grep ' a '
답변
/etc/magic
또는 /usr/share/misc/magic
파일에는 file
파일 유형을 결정하는 데 사용됩니다.
참고 바이너리는 대체 솔루션 일 수 있습니다. 때때로 이상한 인코딩을 가진 파일도 바이너리로 간주됩니다.
grep
Linux의 바이너리 파일을 처리하는 몇 가지 옵션이 있습니다 (예 : --binary-files
또는 -U / --binary
설명
- 더 정확하게는 C99에 따른 인코딩 오류 '의
mbrlen()
. 예제 및 소스 해석 : unix.stackexchange.com/a/276028/32558
Answer
학생 중 한 명이이 문제를 겪었습니다. Cygwin
의 grep
에 버그가 있습니다. 파일에 ASCII가 아닌 문자가있는 경우 grep
및 egrep
는 바이너리로 간주합니다.
댓글
- 버그가 아니라 기능처럼 들립니다.특히 제어 할 수있는 명령 줄 옵션 (-a / –text)이 있습니다.
답변
실제로 “grep이 파일을 바이너리로 간주하게 만드는 이유는 무엇입니까?”라는 질문에 iconv
를 사용할 수 있습니다.
$ iconv < myfile.java iconv: (stdin):267:70: cannot convert
제 경우에는 텍스트 편집기에서 올바르게 표시되는 스페인어 문자가 있었지만 grep은이를 바이너리로 간주했습니다. iconv
출력은 해당 문자의 행 및 열 번호를 가리 킵니다.
NUL
문자의 경우 iconv
는 정상적인 것으로 간주하고 이러한 종류의 출력을 인쇄하지 않으므로이 방법은 적합하지 않습니다.
Answer
같은 문제가있었습니다. 추가 된 문자를보기 위해 vi -b [filename]
를 사용했습니다. 제어 문자 ^@
및 ^M
를 찾았습니다. 그런 다음 vi에서 :1,$s/^@//g
를 입력하여 ^@
문자를 제거합니다. ^M
에 대해이 명령을 반복합니다.
경고 : “파란색”제어 문자를 얻으려면 Ctrl + v 를 누른 다음 Ctrl + M <을 누르십시오. / kbd> 또는 Ctrl + @ . 그런 다음 vi를 저장하고 종료합니다.
Answer
또한이 문제가 있었지만 제 경우에는 일치하는 줄이 너무 깁니다.
file myfile.txt myfile.txt: UTF-8 Unicode text, with very long lines
grep
는 여러 패턴으로 전체 파일을 잘 실행하지만 패턴이 " 매우 긴 줄 "이 Binary file myfile.txt matches
와 함께 중지되었습니다.
-a
를 추가하면이 문제도 해결되지만 NULL 또는 기타 유효하지 않은 문자에 대해 파일을 미리 구문 분석해도 효과가 없습니다 (그렇지 않으면 grep이 다른 패턴에 대해 완료되지 않음). 이 경우 문제가되는 줄에 25,000 개 이상의 문자가 있습니다!
내가 이해하지 못하는 것은 grep
가 줄을 반환하려고 할 때만 발생하는 이유입니다. 다른 패턴을 찾고 있습니다.
--null-data
는NUL
가 구분자입니다.