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

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

나는 이것을 시도했다 :

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.



답변

명확히하기 위해 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
}

답변

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

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

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


답변

마지막 줄이 비어있는 올바르게 종료 된 텍스트 파일은 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.


답변

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