날짜를 기준으로 중복된 파일 이름 제거

날짜를 기준으로 중복된 파일 이름 제거

이와 같은 파일이 수천 개 있습니다.

  • wrfout_d03_2010-06-11_00:00:01
  • wrfout_d03_2010-06-11_00:00:08
  • wrfout_d03_2010-06-12_00:00:20
  • wrfout_d03_2010-06-12_00:00:35
  • wrfout_d03_2010-06-12_00:00:40

첫 번째 타임스탬프만 유지하면 됩니다. 이 경우,

  • wrfout_d03_2010-06-11_00:00:01
  • wrfout_d03_2010-06-12_00:00:20

하나씩 삭제하지 않고도 이 작업을 수행하는 방법을 알 수 있나요? 감사해요!

답변1

그리고 zsh:

typeset -A seen=()
for f (wrfout_d*(N)) (( seen[\${f%_*}]++ )) && echo rm -f $f

echo(결과가 만족스러우면 삭제하세요)

이에 상응하는 내용 bash(bash 4.0 이상 가정)은 다음과 같습니다.

(shopt -s nullglob
typeset -A seen=()
for f in wrfout_d*; do
   (( seen[\${f%_*}]++ )) && echo rm -f "$f"
done)

전역 확장은 어휘순으로 정렬되므로 실제로 시간순과 일치하는 타임스탬프 형식을 사용합니다. 따라서 위에서는 가장 오래된 것부터 가장 어린 것까지 순서대로 파일을 반복하고 가장 짧은 후행( )이 제거된 이름을 본 경우 _*(연관 배열에 기록된 대로) 파일을 삭제합니다. 산술 표현식의 이유는 다음을 참조하세요.${f%_*}$seen A\산술 표현식에서 연관 배열을 안전하게 사용하는 방법은 무엇입니까?

답변2

prev=
for file in wrfout_d*_*_*; do
  head=${file%_*}
  if [ "$head" = "$prev" ]; then
    # Remove "echo" if output is correct
    echo rm -f -- "$file"
  else
    prev=$head
  fi
done

마지막 밑줄 앞의 파일 이름 부분은 변수로 처리됩니다 head. 동일한 문자열에 도달하면 echo rm그렇지 않으면 값으로 설정됩니다.headprevprevhead

답변3

Bash 배열을 사용하는 취약한 솔루션은 다음과 같습니다.

#!/bin/bash

workdir='/home/haxiel/testdir'
prefixes=( $(ls $workdir | cut -d '_' -f 1-3 | sort | uniq) )

for prefix in ${prefixes[@]}; do
files=( $workdir/$prefix* )
unset files[0]
echo rm -- ${files[@]}
done

ls|cut|sort|uniq파이프라인을 사용하여 고유한 접두사 목록을 작성 하고 있습니다 .

그런 다음 접두사를 반복하고 쉘 글로빙을 사용하여 특정 접두사와 일치하는 모든 파일을 가져와 배열에 저장합니다. 첫 번째 파일을 유지하려고 하므로 배열에서 해당 파일을 제거하고 나머지 파일을 명령에 전달합니다 rm.

이 해결 방법은 파일 이름에 특수 문자가 포함되어 있지 않다고 가정합니다. 또한 셸의 정렬 순서가 예상한 정렬 순서와 일치한다고 가정합니다.

스크립트를 작업 디렉터리 외부에 배치해야 합니다. 그렇지 않으면 스크립트 이름이 접두사 중 하나로 캡처됩니다.

한 번 실행하고 출력을 확인하여 올바른 파일을 삭제했는지 확인하십시오. 그런 다음 이전 'echo' 명령을 제거 rm하고 다시 실행하십시오.

언제나 그렇듯이 데이터 삭제는 위험한 과정이므로 주의를 기울이고 필요할 때 백업을 만들어 두세요.

관련 정보