디렉토리의 고유 파일 카운터

디렉토리의 고유 파일 카운터

프로그램을 여러 번 실행했는데 출력이 (약간) 불확실했습니다. 매번 출력을 파일로 인쇄합니다. 나는 현재 많은 텍스트 파일(95,034)을 포함하는 디렉토리를 가지고 있으며 그 중 4개의 서로 다른 고유한 출력이 있을 수 있습니다. 다음 형식으로 출력을 보고 싶습니다.

 A (50,000)
 B (30,000)
 C (10,000)
 D  (5,034)

하지만 A, B, C, D(네 가지 가능한 출력)가 어떻게 보이는지 보는 것만으로도 좋을 것입니다. 90,000개의 파일을 수동으로 중복 제거할 시간이 없습니다. 그렇다면 디렉토리에 있는 고유한 텍스트 파일 수를 어떻게 계산하거나 나열합니까? 감사해요!

답변1

나는 GNU의 열렬한 팬입니다 datamash(https://www.gnu.org/software/datamash/). 다음은 제가 만들고 이 명령을 실행한 시뮬레이션 파일 세트의 샘플 출력입니다.

$ md5sum * | datamash -W -s -g 1 count 2 -f
5591dadf0051bee654ea41d962bc1af0    junk1   27
9c08c31b951a1a1e0c3a38effaca5863    junk2   17
f1e5cbfade7063a0c4fa5083fd36bf1a    junk3   7

해시 값이 5591...인 파일이 27개 있습니다. 그 중 하나는 "junk1"입니다. (마찬가지로 "junk2"와 동일한 파일이 17개, "junk3"과 동일한 파일이 7개 있습니다.)

-W필드 구분 기호로 공백을 사용함을 나타냅니다 . -s -g 1필드 1(예: 해시 값)을 기준으로 정렬 및 그룹화를 나타냅니다 . 필드 1일 수도 있고 count필드 2일 수도 있지만 중요하지 않습니다.

-f"전체 입력 줄을 인쇄합니다"라고 표시됩니다 . 여기에는 특이한 점이 있습니다. 집계된 결과를 인쇄하면 전체 행만 인쇄됩니다.첫 번째각 그룹에서 행을 찾습니다. 이 경우 전체가 아닌 각 반복 세트에 관련된 파일 이름 중 하나를 제공하기 때문에 잘 작동합니다.

답변2

@Isaac의 솔루션을 조금 확장하면 ...

bash문법을 가정 하고 다음과 같이 주어진다.

$ find test -type f
test/AA
test/A
test/C
test/CC
test/B
test/D

그 중 파일 A와 AA는 동일하고, C와 CC도 동일합니다.

다음은 점점 더 효율적인 명령 파이프라인입니다.

$ find test -maxdepth 1 -type f -exec bash -c "md5sum < {}" \; |
    sort -k1,1 |
    uniq --count
      2 102f2ac1c3266e03728476a790bd9c11  -
      1 4c33d7f68620b7b137c0ca3385cb6597  -
      1 88178a003e2305475e754a7ec21d137d  -
      2 c7a739d5538cf472c8e87310922fc86c  -

이제 남은 문제는 md5 해시가 어떤 파일이 A, B, C 또는 D인지 알려주지 않는다는 것입니다. 약간 번거롭기는 하지만 이는 고칠 수 있습니다.

먼저 파일을 하위 디렉터리로 이동하거나, 더 편리하다면 PWD를 이전 디렉터리로 이동합니다. 내 예에서는 작업 .중이고 파일은 test/.

네 가지 파일 형식을 각각 식별하여 파일 A, B, C, D(필요한 경우 파일 Z)에 복사하는 것이 좋습니다.

$ cp -p test/file1002 ./A
...
$ cp -p test/file93002 ./N

등. 이제 각 고유 출력 파일 AZ의 md5 해시를 정의하는 해시 테이블을 구축할 수 있습니다.

$ for file in [A-Z]; do 
      printf "s/%s/%s/\n" "$(md5sum < $file )" "$file"; 
done
s/102f2ac1c3266e03728476a790bd9c11  -/A/
s/4c33d7f68620b7b137c0ca3385cb6597  -/B/
s/c7a739d5538cf472c8e87310922fc86c  -/C/
s/88178a003e2305475e754a7ec21d137d  -/D/

해시 테이블은 sed구문과 유사합니다. 이유는 다음과 같습니다.

find ... md5sum위와 동일한 파이프라인을 실행해 보겠습니다 .

$ find test -maxdepth 1 -type f -exec bash -c "md5sum < {}" \; |
    sort -k1,1 |
    uniq --count

... sed위의 해시 테이블을 사용하여 해시 값을 프로토타입 파일 이름으로 바꾸는 프로세스를 통해 파이프합니다. 명령 sed자체는 다음과 같습니다.

sed -f <(
    for file in [A-Z]; do 
        printf "s/%s/%s/\n" "$(md5sum < "$file")" "$file"; 
    done
)

따라서 이들을 함께 연결하십시오.

$ find test -maxdepth 1 -type f -exec bash -c "md5sum < {}" \; |
    sort -k1,1 |
    uniq --count |
    sed -f <(
        for file in [A-Z]; do 
            printf "s/%s/%s/\n" "$(md5sum < "$file")" "$file"; 
        done
    )
  2 A
  1 B
  1 D
  2 C

다음과 같은 출력이 표시되는 경우:

  2 A
  1 B
  1 5efa8621f70e1cad6aba9f8f4246b383  -
  1 D
  2 C

이는 test/파일의 MD5 값이 파일의 AD와 일치하지 않음을 의미합니다. 즉, E어딘가에 출력 파일 형식이 있습니다. 일단 찾으면( md5sum test/* | grep 5efa8621f70e1cad6aba9f8f4246b383) E에 복사하고 다시 실행할 수 있습니다.

$ cp -p test/file09876 ./E
$ find test -maxdepth 1 -type f -exec bash -c "md5sum < {}" \; |
    sort -k1,1 |
    uniq --count |
    sed -f <(
        for file in [A-Z]; do 
            printf "s/%s/%s/\n" "$(md5sum < "$file")" "$file"; 
        done
    )
  2 A
  1 B
  1 E
  1 D
  2 C

답변3

이 목적으로 sort및를 사용할 수도 있습니다 . uniq파일이 있는 폴더에서 다음을 입력합니다.

find . -type f | awk '{ print "tr \\\\n @ < " $0 "; echo "}' | sh | sort | uniq --count

( 를 사용하지 않는 경우 GNU coreutils 로 교체하세요 uniq --count.)uniq -cuniq

이렇게 하면 한 번에 결과를 얻을 수 있습니다. 단순성과 속도(해싱 방지)를 위해 개행 문자를 다음으로 변환합니다. @이는 원본 파일에 속하지 않는 단일 문자일 수 있습니다.

(하위 폴더에 있는 파일이 있으면 포함된다고 가정합니다. 또 다른 가정은 @파일에 문자가 없다는 것입니다. 그렇지 않은 경우 댓글을 남겨주시면 그에 따라 명령을 조정하겠습니다.)

답변4

해시 맵을 사용하여 모든 고유 파일을 수집합니다. 해시는 콘텐츠에 따라 다르므로 고유한 콘텐츠가 있는 파일만 해시 맵에 항목을 얻게 됩니다.

declare -A unique_files
for file in *; do 
    unique_files["$(md5sum "$file" | cut -d ' ' -f 1)"]="$file"
done
echo "${unique_files[@]}"

관련 정보