사용 가능한 다음 파일 접미사(file_a.txt file_b.txt 등)를 찾는 방법

사용 가능한 다음 파일 접미사(file_a.txt file_b.txt 등)를 찾는 방법

내 시스템은 특정 이벤트가 발생할 때마다 새 텍스트 파일을 생성합니다.
파일 이름 file_a.txt file_b.txt file_c.txt등을 지정해야 합니다.

Bash 쉘 스크립트에서 다음에 어떤 파일 이름을 사용해야 하는지 어떻게 알 수 있나요?

예를 들어 file_a.txtfile_b.txt가 존재하지만 존재하지 않는 경우 file_c.txt사용 가능한 다음 파일 이름은 입니다 file_c.txt.

더 쉬운 경우 숫자일 수 있습니다.
알고리즘 설계를 시작하고 있는데 더 쉬운 방법이 있을까요?

참고: 파일은 매일 삭제되므로 도착 확률 z은 0입니다. 따라서 z모든 전략이 허용됩니다. aa정수, 심지어 UUID도 사용하세요.

답변1

다음은 (오류 검사 없이) bash에서만 수행하는 대략적인 방법입니다.

#helper function to convert a number to the corresponding character
chr() {
  [ "$1" -lt 256 ] || return 1
  printf "\\$(printf '%03o' "$1")"
}

#helper function to convert a character to the corresponding integer
ord() {
  LC_CTYPE=C printf '%d' "'$1"
}

#increment file
fn_incr(){

  #first split the argument into its constituent parts

  local fn prefix letter_and_suffix letter suffix next_letter
  fn=$1
  prefix=${fn%_*}
  letter_and_suffix=${fn#${prefix}_}
  letter=${letter_and_suffix%%.*}
  suffix=${letter_and_suffix#*.}

  #increment the letter part
  next_letter=$(chr $(($(ord "$letter") + 1)))

  #reassemble
  echo "${prefix}_${next_letter}.${suffix}"
}

사용 예:

fn_incr foo_bar_A.min.js
#=> foo_bar_B.min.js

다중 알파벳 인덱싱을 사용하여 bash에서 이 작업을 수행하려면 더 긴 코드가 필요합니다. 언제든지 다른 실행 파일에서 이 작업을 수행할 수 있지만 일괄적으로 파일 이름을 늘리고 싶을 수도 있습니다. 그렇지 않으면 실행 파일의 시작 오버헤드로 인해 프로그램이 허용할 수 없을 정도로 느려질 수 있습니다. 그것은 모두 사용 사례에 따라 다릅니다.

여기서는 9++가 왼쪽으로 오버플로되는 방식을 수동으로 관리할 필요가 없기 때문에 일반 정수를 사용하는 것이 아마도 더 나은 선택일 것입니다.


chr()그리고 ord()뻔뻔하게 훔쳤습니다.알파벳 ASCII 값을 가져오는 Bash 스크립트

답변2

정말로 상관하지 않는다면 Linux에서(보다 정확하게는 다음을 사용하십시오.GNU 핵심 도구):

tmpfile=$(TMPDIR=. mktemp --backup=numbered)
… # create the content
mv --backup=numbered -- "$tmpfile" file.txt

이것은 GNU를 사용합니다백업 이름 지정 체계: file.txt,,,, file.txt.~1~file.txt.~2~

또 다른 상대적으로 간단한 접근 방식은 숫자를 보다 편리한 위치에 배치할 수 있다는 점을 활용하는 것입니다.zsh에 대한 glob 한정자최신 파일을 찾고 일부를 사용하여 다음 파일을 계산합니다.매개변수 확장.

latest=(file_<->.txt(n[-1]))
if ((#latest == 0)); then
  next=file_1.txt
else
  latest=$latest[1]
  next=${${latest%.*}%%<->}$((${${latest%.*}##*[^0-9]}+1)).${latest##*.}
fi
mv -- $tmpfile $next

POSIX 셸과 마찬가지로 앞에 0이 붙은 숫자를 사용하면 더 쉽게 작업할 수 있습니다. 앞에 0이 있는 정수 리터럴은 8진수로 구문 분석됩니다.

move_to_next () {
  shift $(($#-2))
  case ${1%.*} in
    *\*) mv -- "$2" file_0001.txt;;
    *)
      set -- "${1%.*}" "${1##*.}" "$2"
      set -- "${1%_*}" "$((1${1##*_}+1)).$2" "$3";;
      mv -- "$3" "${1}_${2#1}";;
  esac
}
move_to_next file_[0-9]*.txt "$tmpfile"

답변3

노력하다:

perl -le 'print $ARGV[-1] =~ s/[\da-zA-Z]+(?=\.)/++($i=$&)/er' file*.txt

이것은 쉘 글로브 정렬 때문에 file_10.txtafter file_9.txt, file_g.txtafter file_f.txt, file_aa.txtafter 를 제공 file_z.txt하지만 file_ab.txt이후 file_aa.txt또는 file_11.txt이후에는 제공 하지 않습니다.file_10.txtfile*file_z.txt 뒤쪽에 file_aa.txt후에.file_9.txtfile_10.txt

zshfile*.txt(n)대신 을 사용하여 후자의 문제를 해결할 수 있습니다 file*.txt.

zsh또는 이러한 기준으로 가 aa36 abc진법의 숫자로 인식되는 숫자 정렬 순서를 정의할 수 있습니다 .

b36() REPLY=$((36#${${REPLY:r}#*_}))
perl ... file_*.txt(no+b36)

(순서는...7, 8, 9, a/A, b/B..., z/Z, 10, 11...이므로 합계를 섞고 싶지 않습니다 . file_123.txt)file_aa.txt

답변4

python이 문제는 모듈 에서 사용할 수 있는 다양한 반복기 빌딩 블록을 사용하여 쉽게 해결할 수 있습니다.itertools

from os.path import isfile
from string import ascii_lowercase
from itertools import dropwhile, imap, chain, product, repeat, count
next(dropwhile(isfile, imap('file_{}.txt'.format, 
    imap(''.join, chain.from_iterable(
    product(ascii_lowercase, repeat=x) for x in count(1))))))

관련 정보