디렉토리에 많은 파일이 있고 그 중 동일한 접두어를 가진 파일 중 하나만 빼고 모두 삭제하고 싶습니다. 예를 들어, 패턴이 있는 파일이 있습니다 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
'