파일을 하위 디렉터리에서 현재 수준으로 이동하고 파일이 있으면 이름을 바꿉니다.

파일을 하위 디렉터리에서 현재 수준으로 이동하고 파일이 있으면 이름을 바꿉니다.

저는 Mac을 사용하고 있기 때문에 mv는 약간 다르며 해당 --backup속성을 지원하지 않습니다. 제가 생각해 낼 수 있는 최선의 방법은 다음과 같습니다.

find . -mindepth 2 -type f -print -exec mv {} . \;     

답변1

몇 가지 스크립트를 작성해야 합니다. 그것은 다음과 같습니다:

find . -mindepth 2 -type f -print | while read x; do
    y=$(basename "$x")
    if [ -f "$y" ]; then
        mv "$y" "$y".backup
    fi
    mv "$x" "$y"
done

답변2

mv디렉토리가 아닌 경우 target 명령의 단순 백업을 생성하려면 다음을 수행하십시오 .

if [ -e "$target" ] && [ ! -d "$target" ]; then
    mv "$target" "$target.backup"
fi

$target.backup기존 디렉토리라면 분명히 바람직하지 않은 결과를 초래할 것입니다. 또한 기존 항목이 $target.backup있으면 덮어씁니다.

열거 백업 구성표를 사용하는 것이 더 안전합니다.

mv디렉토리가 아닌 경우 target 명령의 열거 백업을 생성하려면 다음을 수행하십시오 .

suffix=1
if [ -e "$target" ] && [ ! -d "$target" ]; then
    while [ -e "$target.$suffix" ]; do
        suffix=$(( suffix + 1 ))
    done

    mv "$target" "$target.$suffix"
fi

그러면 $target파일 이름을 사용하지 않게 $target.N만드는 첫 번째 양의 정수 이름이 변경됩니다 .N$target.N

하지만 여기에는 경쟁 조건이 있다는 점에 유의하세요.다른이 코드의 인스턴스(또는 완전히 관련되지 않은 프로세스)는 $target.$suffix이름이 사용되지 않음을 감지하고 $target해당 이름으로 이동하는 사이에 생성될 수 있습니다.

이를 방지하려면:

suffix=1
if [ -e "$target" ] && [ ! -d "$target" ]; then
    while [ -d "$target.$suffix" ] ||
          ! ln "$target" "$target.$suffix" 2>/dev/null; do
        suffix=$(( suffix + 1 ))
    done
fi

ln이제 우리는새 이름(하드 링크) $target.의 경우 기존 디렉토리의 이름을 생성하는 정수도 건너뜁니다. 무료 새 이름을 찾을 때까지 이 작업은 실패합니다.

그럼 당신은 할 수 있습니다

mv "$source" "$target"

find이전과 마찬가지로 모든 일반 파일을 이동 하려면 다음 명령을 적용하세요 .

find . -mindepth 2 -type f -print -exec sh -c '
    for source do
        target=${source##*/}
        suffix=1

        if [ -e "$target" ] && [ ! -d "$target" ]; then
            while [ -d "$target.$suffix" ] ||
                  ! ln "$target" "$target.$suffix" 2>/dev/null; do
                suffix=$(( suffix + 1 ))
            done
        fi

        mv "$source" "$target"
    done' sh {} +

시험:

$ tree
.
|-- dir1
|   `-- file
|-- dir2
|   `-- file
`-- dir3
    `-- file

3 directories, 3 files
$ # the find command goes here
./dir1/file
./dir2/file
./dir3/file
$ tree
.
|-- dir1
|-- dir2
|-- dir3
|-- file
|-- file.1
`-- file.2

3 directories, 3 files

이 예에서는 가장 최근에 찾은 파일, 이전에 찾은 파일, 첫 번째로 찾은 파일이 file됩니다 .filefile.2file.1find


불행하게도 macOS에서의 구현은 mv -n사용 가능한 종료 상태를 반환하지 않습니다. 실행 실패 시 0이 아닌 값이 반환되면 mv더 적은 경쟁 조건을 사용하여 더 간단한 방법으로 문제를 해결할 수 있습니다.

답변3

이것이 내 최종 결과입니다.

num=1
find . -mindepth 2 -type f -print | while read x; do
    y=$(basename "$x")
    if [ -f "$y" ]; then
        mv "$y" "$y"."$num"
        num=$(( $num + 1 ))
    fi
    mv "$x" "$y"
done

따라서 .backup을 사용하지 마십시오. 동일한 이름을 가진 다른 백업이 있으면 여전히 발생할 수 있습니다. 영감을 주셔서 감사합니다!

관련 정보