덮어쓰기를 방지하기 위해 이동된 파일에 대해 새 이름을 생성하시겠습니까?

덮어쓰기를 방지하기 위해 이동된 파일에 대해 새 이름을 생성하시겠습니까?

동일한 이름을 가진 기존 파일이 있는 경우 파일의 새 이름을 생성하는 방법은 무엇입니까? 데스크탑 환경에서는 파일 이름 끝에 숫자를 추가하여 새 이름을 생성하는데, 명령줄에서는 어떻게 이를 수행할 수 있습니까?

저는 Android OS와 Busybox를 사용하고 있습니다.

답변1

POSIX 쉘이 있다고 가정하면 다음을 수행할 수 있습니다.

mv() {
        eval "DEST=\${$#}" #The destination is the last positional parameter
        if [ -e "$DEST" ] && ! [ -d "$DEST" ];then
                PREFIX=${DEST%.*}
                COUNT=1
                EXT=${DEST##*.}
                args= i=1
                while [ $i -lt $# ]; do args="$args \"\${$i}\"" i=$((i+1)); done
                DEST="$NAME-"$(printf "%03d" $COUNT)".$EXT"
                while [ -e "$DEST" ];do
                    COUNT=$((COUNT+1))
                    DEST="$NAME-"$(printf "%03d" $COUNT)".$EXT"
                done
                eval "command mv $args \"\$DEST\""
        else
                command mv "$@"
        fi
}

이것을 사용하는 방법

이것은 함수이므로 파일에 저장 ~/.bashrc하고 평소처럼 사용하세요 mv.

이것은 무엇을 위한 것인가?

  • 원래 실행 파일의 경로를 변수 mv에 저장합니다.MV
  • 변수로 호출하는 마지막 매개변수를 가져옵니다.DEST
  • 디렉토리가 존재하고 디렉토리가 아닌 경우 DEST, 이 함수는 이름 바꾸기가 파일을 손상시키려고 한다고 가정합니다.
  • 그런 다음 최종 이름의 접두사(최종 이름 앞의 모든 항목 ., 확장명 표시), 확장자(최종 이름 뒤의 모든 항목 .), 개수(있는 경우 최종 이름 뒤의 접두사에 있는 모든 항목 -)를 추출합니다.
  • 추출된 개수는 개수가 없으면 0으로 설정되고, 그렇지 않으면 이전 단계에서 찾은 개수로 설정됩니다.
  • 현재 카운트 증가
  • 그런 다음 함수는 모든 원래 인수(스위치 + 파일 이름)에서 마지막 인수를 뺀 값으로 자신을 호출하고 원래 호출의 마지막 인수 대신 새 파일 이름을 추가합니다. 새 이름은 이전 이름이지만 확장자 앞에 3자리 카운터가 추가됩니다(제로 패딩).
  • 함수는 재귀적입니다. 왜냐하면 다음 호출은 함수 자체여야 하기 때문입니다. 함수가 존재하는 경우 존재하지 않는 새 파일 이름이 발견될 때까지 카운터를 계속 증가시키려고 하기 때문 mv a.txt b.txt입니다 .mv a.txt b-001.txtmvb-001.txt
  • 마지막 인수가 존재하지 않거나 디렉터리인 경우 mv원래 실행 파일은 원래 인수를 사용하여 호출됩니다.

지침

  • 기존 파일을 손상시키려고 반복적으로 시도할 수 있는 횟수는 카운터 길이에 따라 다릅니다(이 경우 999회). 파일을 생성할 수 있는 동안 작동하도록 하려면 파일 시스템의 inode 제한을 포함하는 숫자를 선택할 수 있습니다.
  • 와 유사한 이름을 가진 파일을 손상시키려고 하면 foo-001.txt.foo-001-001.txt

노트

  • 명명 패턴을 변경하려면 명령문을 원하는 대로 3변경하세요 .printf
  • 이 코드는 테스트되었습니다.
  • 이것은 매우 간단하며 일부 극단적인 경우에는 심하게 실패할 것이라고 확신합니다. 문제가 발견되면 기꺼이 해결해 드리겠습니다. 또한 프로덕션 시스템에서는 이 작업을 시도하지 마세요.

답변2

나는 보통 이 도구를 사용하여 mktemp안정적인 임시 파일을 만듭니다. 기본적으로 파일을 생성하지만 -d스위치를 통해 디렉터리를 생성할 수도 있습니다.

현재 디렉터리에 있는 파일의 임시 이름을 만드는 방법은 다음과 같습니다.

$ mktemp somefile.XXXXX
somefile.kiDad

$ mktemp somefile.XXXX
somefile.MrSW

$ mktemp someotherfile.XXXXXXXXXXX
someotherfile.Um4aXKrt3lv

그러면 파일이 생성됩니다.

인용하다

답변3

경고 없이 Joseph의 R 스크립트에 대한 대안이 있습니다! 경로 이름에 숫자 접미사를 추가하고(경로는 디렉터리 또는 파일일 수 있음) 아직 존재하지 않는 접미사를 찾을 때까지 접미사 값을 증가시킵니다. logrotate비슷한 패턴을 사용하지만 새 복사본의 접미사가 항상 "0"이 되도록 기존 복사본을 모두 회전하는 등의 기타 유틸리티도 있습니다 . 이것은 그런 의미에서 회전이 아니기 때문에 이라고 부르 겠습니다 dotmv.file.0가장 오래된복사.

예를 들어:

dotmv somefile.txt

rename somefile.txt somefile.txt.0, 후자가 존재하지 않는 한, 존재하는 경우에는 somefile.txt.1가 됩니다. 여러 파일( dotmv this that "the other thing"등) 을 나열할 수 있으며 모든 파일이 클릭되어 이동됩니다.

나는 이것이 POSIX와 호환된다고 믿습니다. 이것은 set -o posixbash에서 실행됩니다(그러나 이것은 모호한 테스트입니다). 나는 또한 안드로이드(jelly bean 4.2.1) 쉘로 테스트했고 거기서 작동했습니다. 그러나 Android에서는 shebang을 변경하거나 실행하려면 지침을 따라야 합니다 sh dotmv. 루팅된 장치가 없으면 스크립트를 실행 가능하게 만들 수 있는 방법이 없기 때문에 어쨌든 이 작업을 수행하게 됩니다. shebang을 변경하면 exec dotmv.

#!/bin/sh
# On android change that to /system/bin/sh.

# Validate arguments
if [ $# -lt 1 ]; then
    echo "A list of one or more paths is required."
    exit 1
fi

# Checks if a path exists and can be moved.
checkPath () {
    if [ ! -e "$1" ]; then
        echo "'$1' does not exist."
        return 1;
    fi
    if [ ! -w "$1" ]; then
        echo "Cannot move '$1', permission denied."
        return 1;
    fi
    return 0;
}

# Finds a new path with numerical suffix.
getName () {
    suf=0;
    while [ -e "$1.$suf" ]
        do let suf+=1
    done
    Dest=$1.$suf
}

# Loop through arguments -- use quotes to allow spaces in paths.
while (($#)); do
    Src=$1
    Dest=$1
    shift
    checkPath "$Src"
    if [ $? -eq 0 ]; then
        getName "$Src"
        mv "$Src" "$Dest"
    fi
done

여기의 논리는 매우 간단하기를 바랍니다. 이는 Python, C 또는 파일 I/O가 있는 기타 Turing-complete 절차 언어로 구현될 수 있습니다.

관련 정보