파일 이름의 한 인스턴스만 부분적으로 일치시키는 방법은 무엇입니까?

파일 이름의 한 인스턴스만 부분적으로 일치시키는 방법은 무엇입니까?

그래서 이름을 filename:hash.

내가 하고 싶은 일은오직조합을 filename:hash그대로 유지하면서 해시를 일치시키며, 파일이 변경되지 않았기 때문에 해당 해시가 다시 계산되지 않습니다.

이 작업을 수행하는 동안 파일을 이동하거나 삭제해야 하지만 uniq파일 이름이 도구에 대해 충분히 "고유"하지 않게 되므로 파이프를 직접 사용하는 경우에는 작동하지 않습니다.

이를 수행할 수 있는 방법이 있습니까? awk, bash 등과 같은 posix 도구 이외의 다른 도구를 사용하지 않거나 목록 또는 데이터베이스 파일을 사용하지 않습니까?

세부 사항:아니요, 이는 기술적으로 중복되지 않습니다.이것게시물 및, 최종 목표는 기술적으로 동일합니다(예: 다른 게시물이나 여기에서 이미 설명한 방법/시나리오를 사용하여 중복 항목을 제거하거나 이동).

답변1

사용하십시오 bash(실제로 POSIX 도구는 아니지만 명시적으로 언급했기 때문에):

#!/bin/bash

names=( *:* )

printf '%s\n' "${names[@]##*:}" | sort | uniq -c |
while read count hash; do
    if [[ $count -gt 1 ]]; then
        echo 'Would delete/move these:'
        printf '%s\n' *:"$hash"
    fi
done

이는 :현재 디렉토리의 문자를 포함하는 모든 이름을 배열로 수집 합니다 names. 패턴 *:*일치 가정오직우리가 관심있는 파일이며 그러한 이름을 가진 다른 파일은 없습니다.

확장하면 "${names[@]##*:}"해시 값만 포함하는 목록이 생성되며 이를 정렬하고 계산하는 데 사용됩니다 sort | uniq -c.

결과는 count루프 hash로 읽혀지며 while read, 개수가 1보다 크면 해시가 중복되었음을 알 수 있습니다. 해시가 중복되면 패턴은 *:"$hash"해당 해시와 모든 이름을 일치시킵니다.

삭제하고 싶다면모두중복된 해시가 있는 파일의 경우 다음을 수행할 수 있습니다.

rm -f ./*:"$hash"

파일 중 하나를 유지하려면 다음과 같이 할 수 있습니다.

dupnames=( ./*:"$hash" )
rm -f "${dupnames[@]:1}"

그러면 배열이 dupnames일치하는 이름으로 설정되고 파일 시스템에서 첫 번째 배열을 제외한 모든 항목이 제거됩니다.

일부 디버그 출력을 활성화한 상태에서 실행하고 사용할 수 있습니다.rm 장애가 있는첫째, 이것이 실제로 작동한다고 확신할 때까지:

#!/bin/bash

names=( *:* )

printf '%s\n' "${names[@]##*:}" | sort | uniq -c |
while read count hash; do
    if [[ $count -gt 1 ]]; then
        echo 'Would delete/move these:'
        dupnames=( ./*:"$hash" )
        echo rm -f "${dupnames[@]:1}"
    fi
done

sh위의 POSIX 변형:

#!/bin/sh

for name in *:*; do
    printf '%s\n' "${name##*:}"
done | sort | uniq -c |
while read count hash; do
    if [ "$count" -gt 1 ]; then
        echo 'Would delete/move these:'
        set -- ./*:"$hash"
        shift
        echo rm -f "$@"
    fi
done

sort | uniq -c다음으로 제거된 마지막 변형의 변형 awk:

#!/bin/sh

for name in *:*; do
    printf '%s\n' "${name##*:}"
done |
awk '    { count[$0]++ }
     END { for (hash in count) if (count[hash] > 1) print hash }' |
while read hash; do
    echo 'Would delete/move these:'
    set -- ./*:"$hash"
    shift
    echo rm -f "$@"
done

awk조각은 이 답변의 다른 조각을 대체할 수도 있지만 sort | uniq -c이제 최종 루프에서는 개수가 1보다 큰지 여부를 테스트할 필요가 없으며 해시 값만 읽습니다.

관련 정보