주어진 와일드카드 패턴과 일치하는 파일을 제외하고 디렉터리의 모든 파일을 삭제합니다.

주어진 와일드카드 패턴과 일치하는 파일을 제외하고 디렉터리의 모든 파일을 삭제합니다.

디렉토리에 많은 파일이 있고 그 중 동일한 접두어를 가진 파일 중 하나만 빼고 모두 삭제하고 싶습니다. 예를 들어, 패턴이 있는 파일이 있습니다 filename.__<random_string>.pdf. (파일 이름은 특정 길이의 문자열일 수 있습니다.)

foo.__.pdf
foo.__resume.pdf 
foo.__name.pdf
bar.__.pdf
bar.__resume.pdf
bar.__name.pdf

이제 동일한 접두어를 가진 세 개의 파일 중 하나만 원합니다. 즉, 처음 세 개 파일 중 하나와 마지막 세 개 파일 중 하나만 원합니다. 예를 들어 디렉터리에는 다음이 포함되어야 합니다.

foo.__.pdf
bar.__.pdf

모든 스크립팅 언어나 셸을 사용한 답변이 허용됩니다.

답변1

#!/bin/bash

declare -A seen

for name in *.__*.pdf; do
        prefix=${name%%.__*.pdf}

        if [[ -z ${seen[$prefix]} ]]; then
                printf 'keeping "%s"\n' "$name"
                seen[$prefix]=1
        else
                printf 'deleting "%s"\n' "$name"
                # rm -f -- "$name"
        fi
done

*.__*.pdf위 스크립트는 파일 이름 와일드카드 패턴과 일치하는 현재 디렉터리의 모든 파일 이름에서 접두사를 추출합니다. 접두사가 이전에 표시되지 않은 경우 파일은 유지됩니다. 그렇지 않으면 파일이 삭제됩니다( rm이 명령은 현재 보안상의 이유로 주석 처리되어 있습니다).

표시된 접두사를 추적하기 위해 접두사라는 이름의 연관 배열에 키로 저장됩니다 seen. 연관 배열은 bash버전 4에서 도입되었습니다.


*.__*.pdf동일한 접두사와 일치하는 모든 파일은 "동등"하므로 모든 파일의 이름을 동일한 이름으로 바꾸면 단일 파일로 줄어듭니다 .

이는 연관 배열이 필요하지 않으며 다음을 사용하여 쉽게 수행할 수 있습니다 /bin/sh.

#!/bin/sh

for name in *.__*.pdf; do
        prefix=${name%%.__*.pdf}

        printf 'moving "%s" to "%s.__.pdf"\n' "$name" "$prefix"
        # mv -f -- "$name" "$prefix.__.pdf"
done

여기서 접두사가 있는 모든 파일은 foo해당 이름으로 이동됩니다 foo.__.pdf( mv안전을 위해 명령은 주석 처리됨).

답변2

그리고 zsh:

all=(*.__*.pdf)
typeset -A hash
for f ($all) hash[${f%%.__*}]=$f
keep=($hash)
rm -f -- ${all:|keep}

동일한 접두사를 갖는 접두사 중에서 어휘적으로 마지막에 있는 접두사가 유지됩니다. all=(*.__*.pdf(On))reverse를 사용하여 순서를 반대로 할 수 있습니다 all=(*.__*.pdf).

답변3

그리고 zsh:

declare -A h=()
rm -- *(e:'((h[${REPLY%%.*}]++))':)

불행히도 이것은 순서 설정을 허용하지 않습니다. 여기에 o/ glob 한정자를 추가하면 O순서만 변경됩니다.뒤쪽에각 파일의 첫 번째 파일을 제외하고 e파일을 찾은 순서대로 포함/제외할지 여부를 평가합니다(즉, *(oN)순서 없이 반환).

답변4

이를 사용하면 perl현재 디렉터리의 디렉터리 핸들을 열고 이름이 지정된 기준과 일치하는 모든 일반 파일을 읽을 수 있습니다. 동일한 접두어가 있는 첫 번째 파일의 이름은 표준 출력에 인쇄되고 해당 접두어가 있는 후속 파일은 삭제됩니다. 접두사는 해시의 키입니다%h

perl -le '
  opendir my $dh, "."
    or die qq(Cannot opendir ".": $!);

  -f && /^(.+?)\.__.*\.pdf$/ and
    !$h{$1}++ ? print() : unlink()
  while readdir $dh;

  closedir $dh;
'

찾기 명령을 사용하십시오.

fx() {
  set -- "$1" "$tmpdir/${1%%.__*.pdf}"
  if [ ! -s "$2" ]; then
    echo x > "$2"
    shift "$#"
  else
    rm -f "$1"
  fi
  return "$#"
}
export -f fx
tmpdir="$(mktemp -d)" \
find . ! -name . -prune -type f \
-name '?*.__*.pdf' \
-exec sh -c 'fx "$1"' find-sh {} \; -print;

python3과 pathlib 모듈을 사용하면 아이디어는 위와 동일합니다.

python3 -c 'from pathlib import Path
seen = {}
for f in Path(".").glob("?*.__*.pdf"):
  if f.is_file():
    p = f.name.find(".__")
    k = f.name[0:p]
    if p > 0:
      if k in seen: f.unlink()
      else:
        print(f.name)
        seen[k]=1
'

관련 정보