덮어쓰지 않고 이동 또는 복사하고 성공 여부 확인

덮어쓰지 않고 이동 또는 복사하고 성공 여부 확인

질문: 대상 파일(존재하는 경우)을 덮어쓰지 않고 파일 이름을 바꾸거나 파일을 복사한 다음 이동 또는 복사 작업이 성공했는지 확인하는 방법을 찾고 있습니다. MacOS/Unix에 설치된 mv/cp의 BSD 버전과 Linux의 GNU coreutils 버전에서 사용할 수 있는 방법을 찾고 있습니다.

시도해 볼 수 있는 해결 방법: 모든 버전의 mv/cp에서 다음 플래그를 사용하여 대상 파일을 덮어쓰는 것을 방지할 수 있습니다 -n.

mv -n file1 file2
cp -n file1 file2 

비슷한 질문에서는 종료 상태를 사용하여 mv 및 cp가 성공했는지, 성공하면 0인지, 오류가 발생하면 >0인지 테스트하는 것이 좋습니다. 그러나 두 버전의 mv/cp 모두 대상 파일이 이미 존재하고 -n플래그가 사용되는 경우 종료 코드는 0입니다.

내가 생각할 수 있는 유일한 다른 옵션은 해당 -v플래그도 사용하고 명령의 출력을 살펴보는 것입니다.

mv -nv file1 file2
cp -nv file1 file2

-nv그러나 mv/cp의 GNU 및 BSD 버전은 플래그가 사용되고 file2가 이미 존재하는 경우 다르게 동작합니다. mv/cp의 GNU 버전은 아무것도 반환하지 않지만 BSD 버전은 반환합니다 file2 not overwritten.

이전 방법은 먼저 대상 파일이 존재하는지 확인한 다음 mv/cp 작업을 수행하는 것이었습니다. 믿거나 말거나, 검사가 수행되는 시간과 mv/cp 작업이 수행되는 시간 사이에 대상 파일이 다른 프로세스에 의해 생성되는 경우가 있기 때문에 이로 인해 문제가 발생할 수 있습니다.

mv/cp의 BSD 및 GNU 버전을 사용하여 이를 수행할 수 있는 방법이 있습니까?

또는 Python 2를 사용하여 이를 수행할 수 있는 방법이 있습니까? os.rename()을 사용하여 이 작업을 수행하는 방법을 찾을 수 없습니다.

답변1

당신 bash이 가지고 있다면-https://stackoverflow.com/questions/13828544/atomic-create-file-if-not-exists-from-bash-script

set -o noclobber
{ > file ; } &> /dev/null

file이라는 파일이 없으면 이 명령은 file이라는 파일을 생성합니다. file이라는 파일이 존재하는 경우 아무 작업도 수행되지 않습니다(그러나 0이 아닌 반환 코드가 반환됨).

즉, 먼저 이 기술을 사용하여 빈 파일을 만듭니다. 성공하면 빈 파일을 덮어쓸 수 있습니다.

파이썬의 경우에도 마찬가지입니다. 빈 파일을 만드는 데 사용되며 플래그를 os.open()포함해야 합니다 . O_EXCL("플래그 및 모드 값에 대한 설명은 C 런타임 문서를 참조하십시오."POSIX 표준/리눅스 매뉴얼 페이지).


bash 기술은 O_EXCL배후에서 사용됩니다. 게다가RENAME_NOREPLACE, 그러나 Linux에 비교적 새로운 추가 기능이며 OS X에는 존재하지 않는 것 같습니다.

답변2

파일이 동일한 파일 시스템에 있으면하드 링크.

ln SRC DEST

성공하면 소스 파일을 삭제할 수 있습니다.

rm SRC

답변3

cp -nFreeBSD는 파일 덮어쓰기를 요청하면 실패를 반환합니다:

$ rm -f foo.*
$ date > foo.1
$ date > foo.2
$ # this should fail
$ cp -n foo.1 foo.2 || echo fail
fail
$ rm foo.2
$ # this should succeed
$ cp -n foo.1 foo.2 || echo fail
$ exit

맞습니다. mvFreeBSD는 대상이 존재하더라도 성공을 반환합니다.

$ rm -f foo.*
$ date > foo.1
$ date > foo.2
$ # this should fail
$ mv -n foo.1 foo.2 || echo fail
$ exit

한 가지 해결 방법은 다음과 같은 결과 코드를 사용하는 것입니다 &&.mv[ ! -f src-file ]

$ rm -f foo.*
$ date > foo.1
$ date > foo.2
$ # this should fail
$ ( mv -n foo.1 foo.2 && [ ! -f foo.1 ] ) || echo fail
fail
$ rm foo.2
$ # this should succeed
$ ( mv -n foo.1 foo.2 && [ ! -f foo.1 ] ) || echo fail
$ exit

GNU에서는 두 유틸리티 모두 원하는 방식으로 작동하지 않습니다. 동일한 솔루션이 mvUbuntu에서도 작동하므로 GNU가 cp나머지 문제 사례입니다.

그런데, 호출하기 전에 대상 파일의 경쟁 조건을 테스트하는 것에 대한 귀하의 의견을 들었지만 올바른 일을 할 때에도 동일한 경쟁 조건이 발생한다는 cp사실에 충격을 받았습니다 . cp기회의 창은 더 작을 수 있지만 내 직감은 여전히 ​​존재한다는 것입니다. 그러나 IAAE.

해결 방법은 mv두 플랫폼 모두에서 작동하므로 다음 해결 방법으로도 충분할 수 있습니다.

$ rm -f foo.*
$ date > foo.1
$ date > foo.2
$ # this should fail
$ ( cp -n foo.1 TEMPFILE && mv -n TEMPFILE foo.2 && [ ! -f TEMPFILE ] ) || echo fail
fail
$ rm -f TEMPFILE
$ rm foo.2
$ # this should succeed
$ ( cp -n foo.1 TEMPFILE && mv -n TEMPFILE foo.2 && [ ! -f TEMPFILE ] ) || echo fail
$ rm -f TEMPFILE
$ exit

관련 정보