Maildir 디렉토리에 500개의 파일을 grep하고 싶습니다. 나는 명령을 내린다.
grep MyPattern *
오류 메시지가 나타납니다.
bash: /usr/bin/grep: Argument list too long
그래서 파일 목록을 MyFiles 파일에 저장하고 다음 명령을 실행합니다.
for i in $(`cat MyFiles`); do echo $i; done
grep을 실행하기 전에 에코를 수행하여 확인하고 싶습니다. 하지만 이로 인해 다음과 같은 오류가 발생합니다.
bash: 1434361691.M617282P6399V0000000000000808I00000000000E16C1_23.ananda-linux,S=10055:2,S: command not found
여기서 1434...는 디렉터리의 첫 번째 파일입니다.
그럼 원래 질문으로 돌아가겠습니다. 사서함에서 이러한 모든 파일을 찾기 위해 grep하는 방법. 50,000개 이상의 이메일이 들어 있는 더 큰 사서함을 가지고 있습니다.
답변1
grep
현재 디렉터리에서 반복적으로 파일 목록을 구성해 보세요 .
grep -r MyPattern .
이는 하위 디렉토리에서 검색하므로 완전히 동일하지는 않지만 *
메일 디렉토리의 경우 일반적으로 원하는 것입니다.
답변2
쉘이 외부 명령을 실행할 때 명령줄은 파일 이름 와일드카드 패턴(예:)을 확장한 후 *
특정 길이를 초과해서는 안 됩니다 .
귀하의 경우 grep 'PATTERN' *
확장은 쉘이 실행하기에는 너무 긴 명령입니다.
두 번째 예에서는:
for i in $(`cat MyFiles`); do echo $i; done
에 저장된 파일 이름을 반복하려고 시도했지만 MyFiles
구문이 매우 잘못되었습니다.
$(`cat MyFiles`)
동일합니까?
$( $(cat MyFiles) )
이는 내용이 MyFiles
명령으로 해석된다는 의미입니다. 이것이 바로 command not found
오류가 발생하는 이유입니다.
이 문제를 해결하는 방법은 다양하지만 파일 내용을 반복하는 것은 좋은 접근 방식이 아닙니다.
Stephen은 훌륭한 솔루션을 제공했습니다.그의 대답에, 다른 하나는 현재 작업 디렉터리가 Maildir 폴더라고 가정하는 것입니다.
find . -type f -exec grep 'PATTERN' {} +
이 작업은 grep
대규모 파일 배치에 대해 여러 번 수행됩니다.가능한 한 많이.
이는 다음과 유사합니다.
printf '%s\n' * | xargs grep 'PATTERN'
그러나 이 find
명령은 공백과 줄 바꿈이 포함된 파일 이름을 처리합니다.
여기의 명령은 printf
한 줄에 하나의 파일 이름을 출력합니다. grep 'PATTERN' *
대부분의 경우 와 동일한 문제가 발생하지 않습니다 .내장명령이므로 쉘에서 외부 명령으로 실행할 필요가 없습니다.
cat
루프 솔루션도 작동하지만 루프 출력 대신 간단히 다음을 수행할 수 있습니다.
for name in *; do
grep 'PATTERN' "$name"
done
이는 다음과 같이 가정합니다.일반 파일만현재 디렉토리에 있습니다.
메일 메시지만 처리하려면 다음을 사용할 수 있습니다.
for name in *,*; do
grep 'PATTERN' "$name" /dev/null
done
이는 하나 이상의 쉼표가 포함된 이름을 반복합니다. 또한 주어진 패턴과 일치하는 파일 이름을 /dev/null
강제로 출력하도록 추가했습니다 . grep
지원하는 경우 /dev/null
대신 를 제거하고 사용할 수 있습니다 -H
.grep
grep
이러한 루프는 grep
디렉터리의 각 파일에 대해 한 번씩 수행되기 때문에 느립니다.