질문: 대상 파일(존재하는 경우)을 덮어쓰지 않고 파일 이름을 바꾸거나 파일을 복사한 다음 이동 또는 복사 작업이 성공했는지 확인하는 방법을 찾고 있습니다. 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
답변3
cp -n
FreeBSD는 파일 덮어쓰기를 요청하면 실패를 반환합니다:
$ 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
맞습니다. mv
FreeBSD는 대상이 존재하더라도 성공을 반환합니다.
$ 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에서는 두 유틸리티 모두 원하는 방식으로 작동하지 않습니다. 동일한 솔루션이 mv
Ubuntu에서도 작동하므로 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