bash를 사용하여 디렉토리의 모든 파일을 검사하여 어떤 파일(있는 경우)에 내용이 기록되었는지 확인하려면 어떻게 해야 합니까?

bash를 사용하여 디렉토리의 모든 파일을 검사하여 어떤 파일(있는 경우)에 내용이 기록되었는지 확인하려면 어떻게 해야 합니까?

여러 "사람"에 대해 작동하는 스크립트를 실행하고 각 사람에 대한 출력 및 오류 파일을 생성합니다. 이것을 이렇게 표현해보자:

output_alice.txt
error_alice.txt
output_bob.txt
error_bob.txt
.
.
.

error_<name>.txt스크립트가 오류로 종료된 "사람"을 빠르게 식별할 수 있는 방법으로 모든 파일에서 오류( )를 검색하고 콘텐츠가 기록된 파일(비어 있는 파일이 아님)을 에코하는 명령을 원합니다 . 찾을 수 있는 단축키가 있나요? 나는 grep을 사용하여 문자열(예: )로 이 작업을 수행하는 방법을 알고 있지만 grep -r <substring> .거기에 아무것도 있는지 확인하는 방법은 모릅니다.

답변1

bash는 그렇지 않습니다.단말기, 그것은 많은 것 중 하나입니다껍데기, 이는 명령 실행을 전문으로 하는 특정 프로그래밍 언어에 대한 통역사입니다. 대부분의 애플리케이션과 마찬가지로 입력/출력을 터미널 장치나 다른 유형의 파일에 연결할 수 있습니다.

bash 및 대부분의 다른 Unix 쉘 언어에서 현재 작업 디렉토리에 l명명된 행이 하나 이상 포함된 파일을 나열하려면 다음을 수행할 수 있습니다.error_anything.txt

grep -l '^' error_*.txt

^주제의 시작 부분과 일치하는 정규 표현식은 어디에 있습니까?주제파일의 각 줄은 입니다 grep.

비어 있지 않은 텍스트 줄이 하나 이상 있는 사람의 경우:

grep -l . error_*.txt

여기서 .단일 문자와 일치합니다. 로케일과 다른 문자 맵 인코딩을 사용하는 파일은 해당 내용을 텍스트로 디코딩할 수 없는 경우 비어 있지 않은 줄과 일치하지 않을 수 있습니다.

또한 모든 grep구현이 종료되지 않은 줄이 하나만 포함된 파일을 보고하는 것은 아닙니다(의 출력에 표시된 것처럼 하나는 줄 구분 기호가 누락됨 printf invalid-text-as-missing-the-last-newline).

또 다른 방법은 최소 1바이트를 포함하는 파일을 찾는 것입니다.

find -L . ! -name . -prune -name 'error_*.txt' -type f -size +0c

이는 해당 유형이 아닌 파일을 무시하는 이점도 있습니다.정기적인(예: 디렉토리, 소켓...)

또는 zsh 쉘을 사용하십시오.

print -rC1 -- error_*.txt(N-.L+0)

기호 링크의 경우 동작은 대상의 크기와 유형을 고려하여 ullglob 의 동작과 동일합니다(ullglob의 경우 -일치하는 파일이 없으면 오류가 보고되지 않습니다).-L.-type fL+0-size +0cNN

이는 접두사를 포함하지 않는다는 장점이 있으며 ./사용자 이름을 로케일의 텍스트로 디코딩할 수 없는 경우에도 작동하며 (어휘적으로) 정렬된 목록을 제공합니다.

r이를 확장하여 사용자 이름(첫 번째 이름 뒤의 파일 oot 이름 부분 _)만 인쇄할 수 있습니다.

{}{ print -rC1 -- ${@#*_}; } error_*.txt(N-.L+0:r)

error명령을 실행한 이후 수정된 파일을 나열하려면 -newer명령을 실행하기 전에 편집된 파일 의 조건자를 사용하고 find비교할 수 있습니다.touch

touch .before
my-command-that-may-write-to-error-files
find -L . ! -name . -prune -name 'error_*.txt' -type f -size +0c -newer .before

findzsh에서는 명령을 다음으로 바꿀 수 있습니다 .

print -rC1 -- error_*.txt(N-.L+0e['[[ $REPLY -nt .before ]]'])

일부 구현의 경우 로 find바꿀 수 있지만 깊이 0()의 파일은 다른 기준과 일치하지 않기 때문에 여기서도 작동합니다 (일치하지도 않고 일치하지도 않음 ).! -name . -prune-mindepth 1 -maxdepth 1-maxdepth 1.-name 'error_*.txt'-type f

dateand의 GNU 구현 (술어를 도입한 구현 find이기도 함 )을 사용하면 다음을 수행하여 이 파일 생성을 피할 수 있습니다.find-maxdepth.before

before=$(date +'@%s.%N')
my-command-that-may-write-to-error-files
find -L . -maxdepth 1 -name 'error_*.txt' -type f -size +0c -newermt "$before"

를 사용할 때 또는 ( 뒤에 ) 로 zsh바꿀 수 있습니다 . 다시 호출을 피할 수 있습니다.before=$(date +'@%s.%N')print -Pv before '@%D{%s.%N}'before=${(%):-@%{%s.%N}D}before=@$EPOCHREALTIMEzmodload zsh/datetimefind글로벌 예선, 심지어 임시 변수에 대해 익명 함수를 다시 사용하기도 하지만 이는 매우 복잡해집니다.

zmodload zsh/stat
zmodload zsh/datetime
() {
  my-command-that-may-write-to-error-files
  print -rC1 error_*.txt(N-.L+0e['
    stat -F %s.%N -A2 +mtime -- $REPLY && (( $2 > $1 )) '])
} $EPOCHREALTIME

적어도 Linux에서는 시스템과 파일 시스템이 나노초 정밀도를 지원하지만 세분성은 훨씬 더 작습니다. 초기 호출 date이나 참조 보다 이전 값을 수정할 때 수정 시간이 설정되어 있으므로 $EPOCHREALTIME실행하는 데 100분의 1초도 걸리지 않는 명령에는 이러한 방법이 작동하지 않을 수도 있습니다. 1초를 제거 N하고 이를 또는 >로 바꾸는 것이 더 나은 접근 방식일 수 있습니다 ( 구현에서 지원하는 경우 가능성 없음).>=-newer! -olderfind

답변2

GNU는 find빈 파일을 나열하기 위해 POSIX가 아닌 옵션을 제공합니다. 테스트를 무효화하면 됩니다.

find /path/to/dir -type f -name 'error_*.txt' ! -empty

~을 위한아니요-maxdepth 1검색할 경로 뒤에 하위 디렉터리를 추가합니다.

POSIX에서는 find파일 크기 확인이 0가능합니다 .

find /path/to/dir -type f -name 'error_*.txt' ! -size 0

답변3

grep for 는 .모든 문자를 의미합니다. 빈 파일에는 문자가 없으므로 검색 시 .비어 있지 않은 파일이 표시됩니다. 예를 들어:

$ touch empty1 empty2 empty3
$ echo "not empty!" > non_empty
$ ls -l 
total 4
-rw-r--r-- 1 terdon terdon  0 Aug 11 13:13 empty1
-rw-r--r-- 1 terdon terdon  0 Aug 11 13:13 empty2
-rw-r--r-- 1 terdon terdon  0 Aug 11 13:13 empty3
-rw-r--r-- 1 terdon terdon 11 Aug 11 13:13 non_empty

이제 우리는 다음을 grep합니다.

$ grep -- . ./*
non_empty:not empty!

그리고 이름을 알아보세요.

$ grep -l -- . ./*
non_empty

grep .빈 줄(하나 이상의 문자)이 없는 파일은 찾을 수 없습니다 \n. 이를 위해서는 grep '^'제안된 대로 사용해야 합니다.스티븐의 대답.

답변4

GNU sed 전용입니다. 다음 명령의 대안처럼 grep:

sed -sn 1F error_*.txt

! F매뉴얼 페이지에서 명령을 발견하지 못했지만 작동합니다. 특히 비어 있지 않은 파일의 첫 번째 줄에 파일 이름을 삽입합니다.sed -i 1F *

관련 정보