find
이 명령을 사용하여 디렉토리에서 "바이너리가 아닌" 파일을 모두 찾을 수 있습니까 ? 이것이 제가 해결하고 싶은 문제입니다.
Windows 사용자로부터 파일 아카이브를 받았습니다. 아카이브에는 소스 코드와 이미지 파일이 포함되어 있습니다. 우리 빌드 시스템은 Windows 줄 끝이 있는 파일을 잘 처리하지 못합니다. flip -u
*nix와 windows 사이에서 줄 끝을 뒤집는 명령줄 프로그램( )이 있습니다 . 그래서 나는 이런 일을 하고 싶다.
find . -type f | xargs flip -u
그러나 이미지 파일이나 기타 바이너리 미디어 파일에 대해 이 명령을 실행하면 파일이 손상됩니다. 나는 파일 확장자 목록을 작성하고 이를 통해 필터링할 수 있다는 것을 알고 있지만, 그 목록을 최신 상태로 유지하는 데 의존하지 않는 기능을 갖고 싶습니다.
그렇다면 디렉토리 트리에서 바이너리가 아닌 모든 파일을 찾는 방법이 있습니까? 아니면 다른 솔루션을 고려해야 합니까?
답변1
출력을 사용 file
하고 grep 또는 awk로 파이프하여 텍스트 파일을 찾은 다음 file
출력의 파일 이름 부분만 추출하여 xargs로 파이프합니다.
그것은 다음과 같습니다:
file * | awk -F: '/ASCII text/ {print $1}' | xargs -d'\n' -r flip -u
grep은 "텍스트"가 아닌 "ASCII 텍스트"를 검색합니다. 서식 있는 텍스트 문서나 유니코드 텍스트 파일 등을 엉망으로 만들고 싶지 않을 것입니다.
find
다음을 사용하거나 다른 방법으로 확인할 파일 목록을 생성 할 수도 있습니다 file
.
find /path/to/files -type f -exec file {} + | \
awk -F: '/ASCII text/ {print $1}' | xargs -d'\n' -r flip -u
xargs에 대한 인수는 -d'\n'
xargs가 각 입력 행을 별도의 인수로 처리하여 공백 및 기타 문제가 있는 문자가 있는 파일 이름을 처리하도록 합니다. 즉, xargs -0
입력 소스가 NULL로 구분된 출력(예: find
의 옵션)을 생성하지 않거나 생성할 수 없는 -print0
경우 대안 입니다. 변경 로그에 따르면 xargs는 2005년 9월에 -d
/ 옵션을 얻었 --delimiter
으므로 고대가 아닌 모든 Linux 배포판에 있어야 합니다(확실하지 않기 때문에 확인했습니다. 이것이 "최근" 추가 항목이라는 것을 막연하게 기억합니다).
줄 바꿈은 파일 이름의 유효한 문자이므로 파일 이름에 줄 바꿈이 포함되어 있으면 중단됩니다. 일반적인 UNIX 사용자에게 이것은 병리학적으로 미친 일이지만 파일이 Mac 또는 Windows 컴퓨터에서 유래한 경우에는 들어본 적이 없는 일이 아닙니다.
또한 이것이 file
완벽하지는 않다는 점에 유의하십시오. 파일의 데이터 유형을 감지하는 데는 매우 효과적이지만 때로는 혼란스럽습니다.
나는 과거에 이 방법의 변형을 여러 번 성공적으로 사용해 왔습니다.
답변2
find . -type f -exec grep -I -q . {} \; -print
-type f
이는 현재 디렉터리(또는 그 아래)에서 grep
비어 있지 않고 바이너리가 아닌 것으로 간주되는 모든 일반 파일( )을 찾습니다 .
grep -I
바이너리 파일과 비바이너리 파일을 구별하는 데 사용됩니다 . 이 플래그는 파일이 바이너리인 것으로 감지되면 0이 아닌 종료 상태로 종료 -I
되도록 합니다 . grep
에 따르면 grep
"바이너리" 파일은 인쇄 가능한 ASCII 범위 밖의 문자를 포함하는 파일입니다.
주어진 패턴이 발견되면 이 -q
옵션을 사용하면 데이터를 내보내지 않고 종료 상태 0으로 종료됩니다. grep
우리가 사용하는 패턴은 점이며 모든 문자와 일치합니다.
파일이 바이너리가 아니고 최소한 하나의 문자를 포함하는 것으로 확인되면 파일 이름을 인쇄하십시오.
용기가 있다면 flip -u
여기에 코드를 삽입할 수도 있습니다.
find . -type f -exec grep -I -q . {} \; -print -exec flip -u {} \;
답변3
허용된 답변이 나에게 필요한 답변을 모두 찾지 못했습니다. 다음은 -I
grep을 사용하여 바이너리 파일을 무시하고 모든 숨겨진 파일을 무시하는 예 입니다 .
find . -type f -not -path '*/\.*' -exec grep -Il '.' {} \; | xargs -L 1 echo
이것은 실제 응용 프로그램에서 사용됩니다: dos2unix
답변4
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 릴리스, 현재 Arch 및 Ubuntu 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
최신 버전에서는 매개변수와 함께 새 메소드를 사용 -00
하고 file
이전 버전에서는 이전 메소드로 대체하는 바이너리 필터링을 위한 작은 스크립트를 만들었습니다.
#!/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와 유사한 것이 있지만 지원이 필요합니다 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