끝에 빈 줄이없는 파일을 찾는 방법은 무엇입니까?


9

끝에 새 줄이 있거나 없을 수있는 현재 디렉토리의 하위 디렉토리에 파일이 있습니다. 마지막에 줄 바꿈이없는 파일을 어떻게 찾을 수 있습니까?

나는 이것을 시도했다 :

find . -name '*.styl' | while read file; do
    awk 'END{print}' $file | grep -E '^$' > /dev/null || echo $file;
done

그러나 작동하지 않습니다. awk 'END{print}' $file빈 줄 바꾸기 전에 줄을 인쇄합니다 tail -n 1 $file.


@don_crissti 빈 줄이없는 파일이 필요합니다.
jcubic

2
해당 파일을 찾아야하는 이유를 물어봐도 될까요? 유닉스의 텍스트 파일은 줄 바꿈으로 끝나야 한다는 사실과 관련 이 있다고 생각합니다 (vi는 예를 들어 저장할 때 "거의 자동으로"하나 추가합니다). 여러 개의 (텍스트 중심) 명령은 줄 바꿈으로 끝나지 않으면 마지막 줄 (wc, iirc ....하지만 다른 줄이 있습니다). 그리고 이것은 도움 될 것입니다
Olivier Dulac

awk 'END{print}' $file : $ file의 내용을 완전히 무시하고 "$ file"에 포함 된 모든 파일의 구문 분석을 마치면 줄 바꿈이 추가됩니다. awk 명령이 인쇄하는 유일한 방법이므로 : printf '\n'$로 바꾸지 않고 같은 작업을 수행 할 수 있습니다. 나는 이것이 당신이 겨냥한 것이 아니라고 생각합니다 (즉, 파일의 마지막 줄을 인쇄합니까?)
Olivier Dulac

@don_crissti : 파일의 마지막 문자가 개행 문자가 아닌 경우 해당 파일은 유닉스 텍스트 파일이 아닙니다. unix.stackexchange.com/a/263919/27616을 참조하십시오 . 많은 텍스트 명령 (예 : wc)은 개행 문자로 끝나지 않으면 마지막 "줄"을 무시합니다.
Olivier Dulac

1
@OlivierDulac : gawk가 인쇄 c되고 FreeBSD도 마찬가지 입니다. 그러나 gnu.org/software/gawk/manual/… . 그래서 않습니다 하지만 항상 일어난다.
dave_thompson_085

답변:


14

명확히하기 위해 LF (일명 \n또는 줄 바꿈) 문자는 줄 구분 기호 이며 줄 구분 기호 가 아닙니다. 줄 바꿈 문자로 끝나지 않으면 줄이 끝나지 않습니다. a\nb마지막 행 다음에 문자가 포함되어 있기 때문에 포함 된 파일 만 유효한 텍스트 파일이 아닙니다. 가 포함 된 파일에 대해서도 동일합니다 a. 포함 된 파일에는 a\n비어 있지 않은 줄이 하나 있습니다 .

따라서 하나 이상의 빈 줄로 끝나는 파일은 두 개의 줄 바꿈 문자로 끝나거나 단일 줄 바꿈 문자를 포함합니다.

만약:

 tail -c 2 file | od -An -vtc

\n또는을 출력 \n \n하면 파일에 하나 이상의 후행 빈 줄이 포함됩니다. 아무것도 출력하지 않으면 빈 파일이고 출력하면 <anything-but-\0> \n비어 있지 않은 줄로 끝납니다. 다른 것은 텍스트 파일이 아닙니다.

이제 그것을 사용하여 빈 줄로 끝나는 파일을 찾으려면 파일의 마지막 2 바이트 만 읽으므로 효율적으로 (특히 큰 파일의 경우) 효율적이지만 먼저 출력을 프로그래밍 방식으로 쉽게 파싱 할 수 없습니다. 하나의 구현 od에서 다음 구현으로 일관성이 없으므로 파일 당 tail하나씩 실행해야 od합니다.

find . -type f -size +0 -exec gawk '
  ENDFILE{if ($0 == "") print FILENAME}' {} +

(빈 줄로 끝나는 파일을 찾으려면) 가능한 한 적은 명령을 실행하지만 모든 파일의 전체 내용을 읽는 것을 의미합니다.

이상적으로는 파일 끝을 자체적으로 읽을 수있는 쉘이 필요합니다.

zsh:

zmodload zsh/system
for f (**/*(D.L+0)) {
  {
    sysseek -w end -2
    sysread
    [[ $REPLY = $'\n' || $REPLY = $'\n\n' ]] && print -r -- $f
  } < $f
}

이 답변의 방법을 사용하여 일부 파일이 텍스트 파일인지 확인하는 방법 : are_textfiles () { nontext=0; rem="return 0 if all args are files with terminating newline, or n [=number of non-textfiles]" ; for f in "$@" ; do [ -f "$f" ] && { tail -c 1 "$f" | od -An -vtc | grep "\\n" ;} >/dev/null 2>&1 || ((nontext++)) ; done ; return $nontext ; }. 사용 등 :if ( are_textfiles this that otherthing ) ; then echo all are text files ; else echo "are_textfiles returned : $?" ; fi
올리비에 Dulac

6

with gnu sed와 같은 쉘 zsh(또는 bashwith shopt -s globstar) :

sed -ns '${/./F}' ./**/*.styl

각 파일의 마지막 줄이 비어 있지 않은지 확인하여 파일 이름을 인쇄합니다.
당신이 반대를 원한다면 바로 교체 (마지막 줄이 비어있는 경우 파일 이름을 인쇄) /.//^$/


1
-s전에는 실제로 본 적이 없습니다 . GNU 감사합니다!
glenn jackman

참고 : F 옵션은 sed 버전 4.2.2 (2012 년 12 월 22 일)
Isaac

3

마지막 줄이 비어있는 올바르게 종료 된 텍스트 파일은 2로 끝납니다 \n.

그런 다음 tail -c2이 같아야합니다 $'\n\n'.

슬프게도 명령 확장은 후행 줄 바꿈을 제거합니다. 약간의 조정이 필요합니다.

f=filename
nl='
'
t=$(tail -c2 $f; printf x)  # capture the last two characters.
r="${nl}${nl}$"                 # regex for: "ends in two newlines".
[[ ${t%x} =~ $r ]] &&  echo "file $f ends in an empty line"

우리는 줄을 바꾸지 못하는 파일을 확인하기 위해 조금 확장 할 수도 있습니다.

nl='
'
nl=$'\n'
find . -type f -name '*.styl' | while read f; do
    t=$(tail -c2 $f; printf x); r1="${nl}$"; r2="${nl}${r1}"
    [[ ${t%x} =~ $r1 ]] || echo "file $f is missing a trailing newline"
    [[ ${t%x} =~ $r2 ]] && echo "$f"
done

개행은 $'\r\n필요한 경우 와 같이 변경할 수 있습니다 .
이 경우에도로 변경 tail -c2하십시오 tail -c4.


0
for file in *; do
    # Check if the file is readable to avoid clutter
    if cat "./$file" 2&>1 /dev/null; then
        # Compare the last character with a single newline character.
        if [ -n "$(tail -c 1 -- "./$file")" ]; then
            echo "$file"
        fi
        # Also report empty files.
        if [ $(wc -c  < "./$file") -eq 0 ]; then
            echo "$file"
        fi
    fi
done

1
이것은 빈 파일에서는 작동하지 않지만 그와 함께 살 수 있습니다.
jcubic

문자열 비교가 예상대로 작동하지 않기 때문에 더 많은 오류가있을 수 있습니다. 빈 파일 확인을 추가했습니다.
Oskar Skog

아, 개행 문자를 무시합니다.
Oskar Skog

더 읽기 쉽 cat $file 2>&1 /dev/null거나 Bash 전용 인 경우을 고려하십시오 cat $file &> /dev/null.
cat

1
또한, $file그것이 사용되는 모든 곳에서 인용하는 것을 고려 하십시오-그리고 $(commands ...)대신에 사용하십시오 `backticks`...
cat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.