큰 디렉토리의 경우 다른 변수에 저장된 텍스트 문자열이 포함된 줄을 포함하는 파일 이름 변수를 만듭니다.

큰 디렉토리의 경우 다른 변수에 저장된 텍스트 문자열이 포함된 줄을 포함하는 파일 이름 변수를 만듭니다.

150,000개 이상의 파일이 있는 디렉토리가 있습니다. 텍스트 변수에 텍스트가 저장된 모든 파일 목록을 만들고 해당 파일 목록을 다른 변수에 저장하고 싶습니다.

나는 먼저 다음을 시도합니다.

searchtext="Subject: Your"
files = $(grep "$searchtext" ./* | awk '{print ($1)}' )

, 이 방법은 디렉터리에 있는 적당한 수의 파일에 대해 작동하지만 150,000개의 파일이 포함된 디렉터리에서 실행하면 "매개변수 목록이 너무 깁니다."라는 오류가 생성됩니다. (Awk with print는 grep 결과에서 파일 이름만 추출하는 데 사용됩니다.)

files=$(grep "$searchtext" ./* | awk '{print ($1)}') 는 150K 파일 디렉터리에서 작동하지만 실행하는 데 거의 90분이 걸리는 것으로 나타났습니다.

파일에 있는 경우 $searchtext 문자열은 파일 시작 부분에 있습니다. 그래서 grep이 텍스트의 처음 30줄만 표시하도록 제한하면 작업 속도를 크게 높일 수 있다고 생각했습니다. 어떻게 해야할지 모르겠는데 찾아보니디렉토리에 있는 각 파일의 처음 50줄을 어떻게 재귀적으로 grep합니까?거기에서 몇 가지 제안을 시도했습니다. 내 작업에 가장 적합한 것은 다음과 같습니다.

searchtext="Subject: Your"
find . -type f -exec head -n 30 {} + | grep "$searchtext"

이는 허용 가능한 시간 내에 실행되지만 검색 텍스트가 포함된 파일의 파일 이름을 출력하지 않습니다. grep -l을 시도했지만 "find: head' terminated by signal 13 ". Somewhere it was suggested that the using "\" instead of "+" might be more appropriate. However, that also generates an error: "find: missing argument to-exec' "라는 오류가 발생했습니다.

파일 이름이 포함된 grep 결과를 조사할 때 또 다른 문제가 발생할 것으로 예상했습니다. grep 출력을 변수에 할당하려고 하면 다음과 같습니다.

files = $(find . -type f -exec head -n 30 {} + | grep "$searchtext")

"ut1.sh: 16행: 파일: 명령을 찾을 수 없습니다"라는 오류가 발생합니다. 어떤 이유로 "files" 변수가 명령으로 해석됩니까? 내 스크립트 이름은 ut1.sh입니다. 이전에는 문제 없이 여러 번 이런 방식으로 변수를 할당했습니다.

내 bash 버전은 GNU bash, 버전 4.1.2(2)-release (x86_64-redhat-linux-gnu)입니다.

어떻게 완료되었으며 내 시도에 어떤 문제가 있습니까?

감사해요

답변1

일치하는 파일 이름 목록을 얻으려면 스위치를 사용하여 출력을 처리 하지 않고 파일 이름만 가져올 grep수 있습니다. 일치하는 파일의 경우 패턴을 한 번 찾아 중지할 수 있으므로 속도도 더 빠릅니다.-lawkgrep

grep -le "$searchtext" ./* 

간단한 할당으로 출력을 변수에 넣을 수 있습니다(그러나 공백과 와일드카드가 있는 파일 이름은 문제를 일으킬 수 있습니다).

files=$(grep -le "$searchtext" ./* ) 

이것에 관해서는:

find . -type f -exec head -n 30 {} + | grep "$searchtext"

여기의 파이프는 find및 를 구분 grep하므로 각 파일의 처음 30줄을 효과적으로 연결한 다음(여기서 파일 이름을 추적할 수 없음) 결과를 grep합니다. grep -l전체 입력에 일치하는 항목이 있는지 여부만 알려줄 수 있습니다. find각 파일의 합계를 개별적으로 결합 head하려면 내부에서 셸을 실행해야 합니다 grep.

export searchtext
find . -type f -exec sh -c 'head -n 30 "$1" | grep -q "$searchtext" && echo "$1"' sh {} \;

하지만 우리도 awk그렇게 할 수도 있습니다. 이렇게 하면 처음 30줄(GNU awk)에서만 패턴을 찾을 수 있습니다.

awk -vpattern="$searchtext" 'FNR <= 30 && $0 ~ pattern { print FILENAME; nextfile }' *

또는 찾기를 사용하세요:

find . -type f -exec awk -vpattern="$searchtext" 'FNR <= 4 && $0 ~ pattern { print FILENAME; nextfile }' {} +

답변2

bash4.4+ 및 GNU의 경우 grep:

readarray -td '' files < <(grep -rZFle "$searchtext" .)

이메일 파일인 경우 제목을 찾고 있는 것 같으니 여기에서 제목만 검색해 보세요. GNU 사용 awk:

readarray -td '' files < <(
  SEARCH="$searchtext" find . -type f -exec gawk -v ORS='\0' -v RS='\r?\n' '
    $0 == "" {nextfile}
    index($0, ENVIRON["SEARCH"]) {print FILENAME; nextfile}' {} +
)

관련 정보