xargs+ 로find

xargs+ 로find

아래의 while 루프를 사용하여 파일을 읽습니다.

while read file
do
    FileFound="`find $DataDir -name $file -print 2>/dev/null`"
    if [ -n "$FileFound" ]; then
        echo $FileFound >> ${runDir}/st_$Region
        else
            echo $file >> ${APP_HOME}/${Region}_filesnotfound_$date.txt
        fi
done<${Region}_${date}.txt

while 루프는 파일 이름을 읽고 datadir에서 이를 비교하여 일치하는 항목이 있는지 확인합니다. 사용 가능한 경우 전체 경로를 파일에 넣습니다. 사용할 수 없는 경우 다른 파일에 저장됩니다. 그러나 이 스크립트는 8000개의 레코드를 읽는 데 2일이 걸립니다. 최적화할 수 있는 방법이 있나요?

답변1

최신 Linux 데스크톱을 사용하는 경우 다음과 같은 파일 인덱싱 도구가 있을 것입니다.mlocate백그라운드에서 파일이 이미 설치되어 색인화 중입니다. 그렇다면 다음을 사용할 수 있습니다.

while read file
do
    locate "$file" >> "${runDir}/st_$Region" || echo "$file" >> "${APP_HOME}/${Region}_filesnotfound_$date.txt"
done<"${Region}_${date}.txt"

찾고 있는 파일이 자주 업데이트되는 경우 먼저 데이터베이스 업데이트를 수동으로 강제 실행할 수 있습니다.updatedb아니면 귀하의 버전에 맞는 것이 무엇이든 가능합니다 locate.

답변2

xargs+ 로find

xargs한 가지 해결책은 매우 긴 명령을 사용하여 find수천 개의 파일을 한 번에 검색하는 것입니다.

sed -e 's/^/-o -name /' "${Region}_${date}.txt" \
| xargs find "$DataDir" -false \
> "${runDir}/st_$Region"

첫 번째 명령은 각 파일 이름을 sed명령에 추가될 표현식으로 변환합니다. 그런 다음 빌드된 명령을 실행합니다. 결과는 파일에 직접 저장됩니다.-o -name filenamexargsfindxargsfindst_$Region

아름다운. 하지만 ${Region}_filesnotfound_$date.txt찾을 수 없는 파일 목록을 어떻게 작성합니까 ? 발견된 파일 목록과 전체 원본 목록을 교차시키면 됩니다.

comm -3 \
    <(sort -u "${Region}_${date}.txt") \
    <(xargs -L1 basename < "${runDir}/st_$Region" | sort -u) \
    > "${Region}_filesnotfound_$date.txt"

comm -3두 파일 사이의 공통 줄을 억제합니다. 이것은 실제로 가짜 파일입니다. 두 번째 파일은 basename발견된 각 파일에 명령을 적용한 결과입니다. 두 파일이 모두 정렬되었습니다.

find+ 로grep

또 다른 해결책은 (옵션을 grep통해 find) 파일에 저장된 일련의 패턴을 검색할 수 있는 가능성을 제공하는 것입니다 grep. -f파일에는 일련의 파일 이름이 있습니다. 이것을 패턴 목록으로 만들어서 다음에 공급해 보겠습니다 grep.

find "$DataDir" \
| grep -f <(sed 's|.*|/&$|' "${Region}_${date}.txt") \
> "${runDir}/st_$Region"

sed명령은 필수입니다. 검색할 파일 이름을 경로 끝에 고정합니다.

누락된 파일 목록은 다른 솔루션과 동일한 방식으로 구축됩니다.

이 해결 방법의 문제점은 파일 이름에 grep: ., 등 으로 해석될 수 있는 문자가 포함될 수 있다는 것입니다 *. [우리는 이것을 사용하여 그것들을 탈출해야 합니다 sed(나는 이것을 독자들에게 연습으로 남겨둡니다). 이것이 첫 번째 솔루션이 IMHO를 선호하는 이유입니다.

마지막으로 여기서는 몇 가지 주의 bash(예: 절차적 대체 <(...))를 사용하고 있습니다. 내 솔루션이 POSIX와 호환될 것이라고 기대하지 마십시오.

답변3

이 스크립트는 특정 파일이 1회 발생하는 경우에만 작동합니다. 따라서 서로 다른 디렉터리에 동일한 이름을 가진 두 개의 파일이 있는 경우 하나만 보고됩니다. 아직 테스트되지 않았습니다.

declare -a arr
tmp1=$$tmp1

while read file
do
    base=$(basename "$file")
    echo "$base" >> "$tmp1"
    arr["$base"]="$file"
done <(find "$DataDir")

cat "$tmp1" | sort | uniq > "$tmp1"
tmp2=$$tmp2
cat "${Region}_${date}.txt" | sort | uniq > "$tmp2"

for file in "$(join <(cat "$tmp1") <(cat "$tmp2"))"
do
    echo "${arr["$file"]}" >> ${runDir}/st_$Region
done

for file in "$(cat "$tmp1" "$tmp2" | sort | uniq -u)"
do
    echo "$file" >> ${APP_HOME}/${Region}_filesnotfound_$date.txt
done

rm "$tmp1"
rm "$tmp2"

답변4

이 스크립트의 느린 부분은 find전체 파일 $DataDir에서 일치하는 항목을 검색하는 것입니다. 이 구성 요소의 대부분을 루프 밖으로 이동하면 많은 시간을 절약할 수 있습니다.

ftmp=$(mktemp -t)
find "$DataDir" >"$ftmp" 2>/dev/null

while IFS= read -r file
do
    if grep -Fx -q "$file" "$ftmp"    # No RE patterns. Match full line
    then
        echo "$file" >>"$runDir/st_$Region"
    else
        echo "$file" >>"${APP_HOME}/${Region}_filesnotfound_$date.txt"
    fi
done <"${Region}_${date}.txt"

rm -f "$ftmp"

파일 목록이 ${Region}_${date}.txt매우 큰 경우 전체 파일을 전달한 grep다음 comm전체 목록 및 일치 세트에서 일치하지 않는 항목을 식별하여 추가로 저장할 수 있습니다. 여기서 단점은 comm목록을 정렬해야 하기 때문에 출력 결과 목록도 정렬된다는 것입니다.

fdata=$(mktemp -t)
fmatch=$(mktemp -t)
find "$DataDir" >"$fdata" 2>/dev/null

# No RE patterns. Match full line
grep -Fx -f "${Region}_${date}.txt" "$fdata" |
    tee -a "$runDir/st_$Region" |
    sort >"$fmatch"

# Pick out the filenames that didn't match
sort "${Region}_${date}.txt" |
    comm -23 - "$fmatch" >>"${APP_HOME}/${Region}_filesnotfound_$date.txt"

rm -f "$fdata" "$fmatch"

관련 정보