모든 "비 이진"파일 찾기


43

find명령 을 사용하여 디렉토리에서 "이진이 아닌"파일을 모두 찾을 수 있습니까? 해결하려는 문제가 있습니다.

Windows 사용자로부터 파일 아카이브를 받았습니다. 이 아카이브에는 소스 코드와 이미지 파일이 포함되어 있습니다. 우리의 빌드 시스템은 Windows 줄 끝이있는 파일로는 훌륭하지 않습니다. flip -u* nix와 windows 사이의 줄 끝을 뒤집는 명령 줄 프로그램 ( )이 있습니다. 그래서 저는 이런 식으로하고 싶습니다

find . -type f | xargs flip -u

그러나이 명령을 이미지 파일 또는 기타 이진 미디어 파일에 대해 실행하면 파일이 손상됩니다. 나는 파일 확장자 목록을 작성하고 그로 필터링 할 수 있다는 것을 알고 있지만 오히려 그 목록을 최신 상태로 유지하는 것에 의존하지 않는 것을 원합니다.

디렉토리 트리에서 모든 이진이 아닌 파일을 찾는 방법이 있습니까? 아니면 고려해야 할 대체 솔루션이 있습니까?


1
file스크립트 / 파이프 라인 어딘가에서 유틸리티를 사용하여 파일이 데이터인지 텍스트인지 식별 할 수 있습니다.
lk-

1
이진이 아닌 것은 무엇을 의미합니까 (현대 컴퓨터의 모든 것은 이진입니다). 텍스트 및 이진 파일이있는 이전 C / PM 운영 체제와의 차이점을 사용하고 있다고 생각합니다. 텍스트 파일의 길이는 제한이 없지만 ctrl-z로 끝나야하며 이진 파일은 512 바이트 블록의 배수 여야합니다. 그렇다면 텍스트 파일을 의미합니다. (또한 이진 파일이 아닌 파일로 끝나는 줄에 대해 쓴다는 점에 주목하십시오. 텍스트 파일임을 나타냅니다.) 맞습니까?
ctrl-alt-delor

모든 파일은 바이너리이며 해석의 문제 일뿐입니다. 텍스트 파일을 찾는 방법을 묻고 있습니까?
ctrl-alt-delor

@richard 저는 일반 텍스트 일반 텍스트 로 해석되는 파일과 다른 모든 파일 (이미지, 워드 프로세싱 문서 등) 이진으로 불리는 시대를 맞이했습니다 . 나는 후드 아래에있는 모든 것을 1과 0으로 알고 있습니다 :)
Alan Storm

1
아, 나는 당신이 내 용어에 대해 당신이 무엇을 의미하는지 봅니다. 혼란을 피하기 위해 앞으로 바이너리 / 텍스트를 사용할 것입니다. Re : \ r \ n 일-타자기 캐리지 리턴 (행의 시작으로 이동) 및 줄 바꿈 (한 줄 아래로 이동)에 대한 ASCII 문자라는 것을 이해합니다. 따라서 \ r \ n은 줄 끝 문자의 실제 물리적 인 "보다 정확한"모델입니다. OS X 이전의 Mac에서는이를 위해 \ r 만 사용했습니다. 나는 보통 모든 것을 "우리가 여전히 다루고있는 서두르는 임의의 선택"으로 기록합니다
Alan Storm

답변:


20

file출력을 grep 또는 awk로 사용 하여 파이프하여 텍스트 파일을 찾은 다음 file출력 의 파일 이름 부분 만 추출 하고 xargs로 파이프합니다.

같은 :

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

grep은 단지 'text'가 아닌 'ASCII text'를 검색합니다. 리치 텍스트 문서 나 유니 코드 텍스트 파일 등을 엉망으로 만들고 싶지는 않을 것입니다.

find(또는 무엇이든)을 사용 하여 검사 할 파일 목록을 생성 할 수도 있습니다 file.

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

-d'\n'xargs에 대한 인수는 xargs가 각 입력 행을 별도의 인수로 취급하므로 공백 및 기타 문제가있는 문자가있는 파일 이름을 제공합니다. 즉 xargs -0, 입력 소스가 NULL로 구분 된 출력 (예 : find's -print0옵션)을 생성 할 수 없거나 생성 할 수없는 경우에 대한 대안 입니다. changelog에 따르면, xargs는 2005 년 9 월에 -d/ --delimiter옵션을 얻었 으므로 고대 리눅스 배포판이 아니어야합니다.

줄 바꿈은 파일 이름에 유효한 문자이므로 파일 이름에 줄 바꿈이 있으면 줄 바꿈됩니다. 일반적인 유닉스 사용자의 경우 병리학 적으로 좋지 않지만 파일이 Mac 또는 Windows 시스템에서 시작된 경우 들어 본 적이 없습니다.

또한 file완벽하지는 않습니다. 파일에서 데이터 유형을 감지하는 데는 좋지만 때때로 혼란 스러울 수 있습니다.

나는 과거에이 방법의 많은 변형을 여러 번 사용 해왔다.


1
이 솔루션에 감사드립니다! 어떤 이유로 든 내 Solaris 시스템이 아닌 file표시 되므로 해당 부분을 적절히 수정했습니다. 또한 동등한 것으로 대체되었습니다 . English textASCII textawk -F: '{print $1}'cut -f1 -d:
Andrew Cheong

3
grep -I필터 바이너리를 말할 가치가있는
xenoterracide

단어를 찾는 text것으로 충분합니다. 또는 또는 file과 같은 설명을 선택합니다 . ASCII Java program textHTML document texttroff or preprocessor input text
user1024

내 답변 은이 답변에 대한 부분적으로 답변 / 개선입니다. ASCII textRTF 엉망을 피하기 위해 grepping에 대한 아주 좋은 지적 .
와일드 카드

1
xenoterracide : 당신은 내 생명을 구했습니다! 그냥 플래그 -I와 BINGO
Sergio Abreu

9

아니요. 이진 또는 비 이진 파일에는 특별한 것이 없습니다. '0x01–0x7F의 문자 만 포함'과 같은 휴리스틱을 사용할 수 있지만 비 ASCII 문자 이진 파일이있는 텍스트 파일과 불행한 이진 파일 텍스트 파일이 호출됩니다.

일단, 당신이 그것을 무시하면 ...

zip 파일

Windows 사용자가 zip 파일로 오는 경우 zip 형식은 파일을 아카이브 자체에서 이진 또는 텍스트로 표시하는 것을 지원합니다. unzip의 -a옵션을 사용 하여 이것에주의를 기울이고 변환 할 수 있습니다. 물론 이것이 왜 좋은 생각이 아닌지에 대한 첫 번째 단락을보십시오 (zip 프로그램이 아카이브를 만들 때 잘못 추측했을 수 있습니다).

zipinfo는 압축 파일 목록에서 이진 (b) 또는 텍스트 (t) 파일을 알려줍니다.

다른 파일들

파일 명령은 파일을보고 식별하려고합니다. 특히, -i(출력 MIME 유형) 옵션이 유용 할 것입니다. text / * 유형의 파일 만 변환


6

다음을 bash사용하여 이진이 아닌 파일 만 처리하는 일반적인 솔루션 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)

파일 유틸리티 작성자에게 연락하여 -00버전 5.26 (2016-04-16 릴리스, 현재 아치 및 우분투 16.10에 있음)에 멋진 매개 변수를 추가하여 file\0result\0여러 파일을 한 번에 공급하여 인쇄 할 수 있습니다. 예 :

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

(이 awk부분은 이진이 아닌 모든 파일을 필터링하는 것입니다. ORS출력 구분 기호입니다.)

물론 루프에서도 사용할 수 있습니다.

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}')

이것과 이전을 기반으로 나는 새로운 버전의 매개 변수를 bash사용하여 새로운 방법을 사용하고 이전 버전의 이전 방법으로 돌아가는 이진 파일을 필터링 하는 작은 스크립트를 만들었습니다 .-00file

#!/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

또는 여기 더 POSIX-y 하나이지만 다음을 지원해야합니다 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

받아 들여진 대답은 나를 위해 모든 것을 찾지 못했습니다. 다음은 grep을 사용하여 -I바이너리를 무시하고 모든 숨겨진 파일을 무시 하는 예입니다 ...

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

실제 응용 프로그램에서 사용 중입니다 : dos2unix

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


4

Cas의 대답 은 좋지만 정상적인 파일 이름을 가정합니다 . 특히 파일 이름에 줄 바꿈이 포함되지 않는다고 가정합니다.

이 경우를 올바르게 처리하는 것이 매우 간단하고 실제로는 더 깨끗하기 때문에 여기 에서이 가정을할만한 이유가 없습니다.

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

find명령은 POSIX 지정 기능 만 사용 합니다 . 사용 -exec부울 시험으로 임의의 명령을 실행하는 것은 간단하고 강력한 (정확하게 핸들 홀수 파일명) 및 이상 휴대용 -print0.

실제로 명령의 모든 부분은를 제외하고 POSIX에 의해 지정됩니다 flip.

참고 file가 반환하는 결과의 정확성을 보증하지 않습니다. 그러나 실제로 출력에서 ​​"ASCII 텍스트"를 grepping하는 것은 매우 안정적입니다.

( 일부 텍스트 파일 이 누락 되었을 있지만 이진 파일을 "ASCII 텍스트"로 잘못 식별하여 엉망으로 만들 가능성이 매우 낮으므로주의해야 할 부분이 있습니다.)


인수가없는 파일 calls은 속도가 느릴 수 있습니다. 예를 들어 비디오의 경우 인코딩에 대한 모든 정보를 알려줍니다.
phk

또한로 시작하는 파일이 없다고 가정합니다 -.
phk

그리고 한 번만 호출하지 않는 이유는 없습니다 file. 여러 파일을 인수로 사용할 수 있습니다.
phk

@phk, 귀하의 의견을 해결하기 위해 : (1) 잠재적 인 속도 저하를 아는 것이 좋지만 POSIX는이를 방지 할 방법이 없습니다. (2) 명령이 쉘 명령에 전달 된 모든 파일 이름 앞에 붙기 때문에 파일 이름에 대해 전혀 가정 하지 않습니다. (3) 한 번에 단일 명령 출력에서 테스트로 사용 하는 것이 줄 바꿈이 포함될 수있는 파일 이름을 올바르게 처리 할 수있는 유일한 POSIX 방법입니다. find./grepfile
와일드 카드

최종 "POSIX-y"솔루션을 살펴본 결과, 영리하다고 생각합니다. 그러나 POSIX에서 보장 하지 않는 플래그와 구분 기호 를 file지원 한다고 가정합니다 . --mime-encoding--
와일드 카드

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

-type f현재 디렉토리 (또는 아래) grep에서 비어 있지 않고 이진이 아닌 것으로 생각되는 모든 일반 파일 ( )을 찾을 수 있습니다.

grep -I이진 파일과 이진이 아닌 파일을 구별 하는 데 사용 됩니다. -I플래그와는 원인이됩니다 grep이 파일이 이진 감지하면 0이 아닌 종료 상태로 종료합니다. 에 따르면 "이진"파일은 grep인쇄 가능한 ASCII 범위 밖의 문자를 포함하는 파일입니다.

-q옵션을 사용하는 grep지정된 패턴이 데이터를 방출하지 않고, 발견되는 경우가 제로 (0) 종료 상태로 종료하게됩니다. 우리가 사용하는 패턴은 하나의 점으로 모든 문자와 일치합니다.

파일이 이진이 아닌 것으로 확인되고 하나 이상의 문자가 포함되어 있으면 파일 이름이 인쇄됩니다.

당신이 용감하다고 느끼면, 당신도 flip -u그것을 연결할 수 있습니다 :

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

1

이 시도 :

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

의 인수는 grep '[^ -~]'입니다 '[^<tab><space>-~]'.

쉘 명령 행에 입력하면 Ctrl+ Vbefore를 입력하십시오 Tab. 편집기에서는 아무런 문제가 없어야합니다.

  • '[^<tab><space>-~]'ASCII 텍스트가 아닌 모든 문자와 일치합니다 (캐리지 리턴은 무시 됨 grep).
  • -L 일치하지 않는 파일의 파일 이름 만 인쇄합니다
  • -Z널 문자로 구분 된 파일 이름을 출력합니다 (for xargs -0).

Perl과 같은 정규식 grep -P(사용 가능한 경우) \t을 사용할 수 있다는 점은 주목할 가치 가 있습니다. 또는 쉘이 지원하는 경우 로케일 변환 사용 : $'\t'( bashzsh수행).
phk

1

대체 솔루션 :

dos2unix 명령은 줄 끝을 Windows CRLF에서 Unix LF로 변환하고 자동으로 이진 파일을 건너 뜁니다. 다음을 사용하여 재귀 적으로 적용합니다.

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

이후 dos2unix인수로 여러 파일 이름을 걸릴 수 있습니다, 할 훨씬 더 효율적이다find . -type f -exec dos2unix {} +
안톤

0

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

i. (-type f -and -path '* / git / *'-iname 'README') : 이름이 git 인 파일과 이름이 README 인 파일을 경로 내에서 검색합니다. 검색 할 특정 폴더와 파일 이름을 알고 있으면 유용합니다.

ii.-exec 명령은 find로 생성 된 파일 이름에서 명령을 실행합니다.

iii. \; 명령의 끝을 나타냅니다

iv. {}는 이전 찾기 검색에서 찾은 파일 / 폴더 이름의 출력입니다.

v. 여러 명령을 나중에 실행할 수 있습니다. -exec "command"를 추가하여; 예를 들어 -exec flip -u \;

vii. 그렙

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. 

이 테스트 디렉토리를 복제하고 사용해보십시오 : https://github.com/alphaCTzo7G/stackexchange/tree/master/linux/findSolution204092017

자세한 답변은 여기 : https://github.com/alphaCTzo7G/stackexchange/blob/master/linux/findSolution204092017/README.md

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