mv : 대상이없는 경우에만 파일 이동


44

내가 사용할 수 mv file1 file2에만 이동하는 방법 file1file2경우 file2존재하지 않는?

난 노력 했어

yes n | mv -i file1 file2

(이것은 mvfile2를 재정의하고 자동으로 아니오로 대답 해야하는지 묻습니다.) 학대 외에도 -i멋진 오류 코드를 제공하지 않습니다 (이동하면 항상 0 대신 141, 이동하지 않으면 다른 것)


3
pipefail종료 상태가 141 yes이므로 mv여기서 SIGPIPE를 얻을 이유가 없으므로 옵션을 설정 해야합니다 .
Stéphane Chazelas

file2가 디렉토리 인 경우에도이 방법이 실패합니다 (file1을 file2 디렉토리로 이동 함). GNU mv는이를 -T위한 것입니다.
Stéphane Chazelas

@ StéphaneChazelas 욕구가 mv아닌 출구 상태를 사용하려는 경우 yes가장 간단한 해결책은 다음과 같습니다.mv -i file1 file2 < <(yes n)
kasperd

답변:


63

mv -vn file1 file2. 이 명령은 원하는 것을 수행합니다. -v원하는 경우 건너 뛸 수 있습니다 .

-v mv가 파일을 이동하면 파일이 이동되었다고 알려줍니다 (파일이 이동하지 않을 가능성이 있기 때문에 유용합니다)

-n file2가없는 경우에만 이동합니다.

있다는 점에 유의하시기 바랍니다 이 POSIX 아니다 으로 ThomasDickey 언급 .


2
그러나 POSIX 가 아닙니다 .
Thomas Dickey

1
@ThomasDickey POSIX는 이것을 원자적인 방식으로 전혀 지원하지 않습니까?
Fabian Schmitthenner

3
@Fabian에게 : 아마도 그렇지는 않지만 제안 된 답변 내에서도 도구 작성 방식에 따라 도구 내에서 경쟁 할 가능성이 있습니다.
Thomas Dickey

3
이것은 레이스가없는 것 같습니다 strace. 내 시스템에서 사용 하고 있음을 보여줍니다 : stat ( "file2", 0x7ffe3e705d10) = -1 ENOENT (이러한 파일이나 디렉토리가 없음) lstat ( "file1", {st_mode = S_IFREG | 0644, st_size = 0, ...}) = 0 lstat ( "file2", 0x7ffe3e705a10) = -1 ENOENT (해당 파일 또는 디렉토리가 없음) rename ( "file1", "file2") = 0 lseek (0, 0, SEEK_CUR) = -1 ESPIPE (잘못된 탐색). 따라서 이름 바꾸기가 사용 된 것 같습니다. @ StéphaneChazelas 솔루션은 실제로 무료 경주를하고 싶다면 올바른 솔루션으로 보입니다.
Fabian Schmitthenner

2
왜 사용하지 않는지 궁금합니다renameat2
Fabian Schmitthenner

16

mv -n

에서 man mv는 GNU 시스템 :

-n, --no-clobber
는 기존 파일을 덮어 쓰지 않습니다.

FreeBSD 시스템에서 :

-n기존 파일을 덮어 쓰지 마십시오. -n 옵션은 이전의 모든 -f 또는 -i 옵션보다 우선합니다.


10
if [ ! -e file2 ] && [ ! -L file2 ]
then
    mv file1 file2
# else echo >&2 there is already a file2 file.
fi

또는:

if ! ls -d file2 > /dev/null 2>&1
then
    mv file1 file2
fi

존재하지 않는 mv경우 에만 실행 됩니다 file2. 그것은이 보장되지 않습니다 file2A를하기 때문에 오버라이드 (override)되지 않습니다 file2테스트와 사이에 생성 된 수있는 mvGNU의 이상 최신 버전에서,하지만 참고 mv-i또는 -n경쟁 조건이 좁아은 비록 그 보증 중 하나를 (제공하지 않습니다 에서 확인이 완료되었으므로 mv).

다른 한편으로는 이식성이 뛰어나 케이스를 구별 할 수 있으며 file2파일 유형 (일반, 파이프, 심지어 디렉토리 )에 관계없이 작동합니다 .


3
이것은 존재 확인과 이동 사이에 파일을 쓸 수있는 경쟁 조건을 도입합니까?
Fabian Schmitthenner

3
당신이 무엇이든 항상 가능성.
Majenko

3
Linux API에는 플래그를 renameat2제공 할 수 있습니다 RENAME_NOREPLACE. 나는 이것이 원자 적으로 파일 존재를 확인한 다음 파일을 옮긴다 고 생각합니다.
Fabian Schmitthenner

디렉토리의 경우 -d, 링크의 경우 -l 또는 모든 파일 유형의 경우 -e
Majenko

이름 변경은 경쟁이 없을 수 있지만 나머지 mv 명령은 그렇지 않습니다. 연결을 해제 할 필요가 없다고 생각하면 갑자기 이름 바꾸기가 실패하고 오류가 발생합니다.
Majenko

8

ln제공된 GNU를 이용한 무인 접근 방식 file1디렉토리 유형이 아닙니다 .

ln -PT file1 file2 && rm file1

어떤 것을 보장 (일부 네트워크 파일 시스템의 버그를 제외하고) file2파일을 재정의 얻을 것이다 (또는 경우에 것을 file2형 디렉토리이며, file1그것으로 이동되지 않습니다)에 있기 때문에 link()시스템 호출의에 반하는 rename()경우 생성 시스템 호출은 실패합니다 대상이 존재합니다.

그러나, 파일로 모두 존재하는 중간 상태가 될 것입니다 file1file2.

-T옵션 (항상 할 link("file1", "file2")경우에도 file2형 디렉토리의 것은) GNU 다릅니다.

다음 link명령을 사용할 수도 있습니다 .

link file1 file2 && rm file1

그러나 file1구현에 따라 심볼릭 링크 인 경우 file2해당 심볼릭 링크 또는 해당 심볼릭 링크의 대상에 대한 하드 링크가됩니다 (Solaris에서는 /usr/sbin/link, not 사용 /usr/xpg4/bin/link).


2
renameat2플래그 RENAME_NOREPLACE가 있는 리눅스 API 가 원자인지 아십니까?
Fabian Schmitthenner

1
@Fabian, AFAICT는 새로운 기능이며 모든 파일 시스템에서 지원되지는 않습니다. 앞으로 Linux에서 향후 mv 구현에서이를 사용할 것으로 예상 할 수 있습니다. 그것이 설계된 것입니다.
Stéphane Chazelas

0

test -e name이름이 존재하면 (파일, 디렉토리 또는 심볼릭 링크에 관계없이) true를 반환하는를 사용할 수도 있습니다 .

예를 들면 다음과 같습니다.

touch file
mkdir dir
ln -s file symlink
test -e file && echo file exists
test -e dir && echo dir exists
test -e symlink && echo symlink exists
test -e file || echo you wont see this echo
test -e doesnotexist || echo doesnotexist does not exist...

1
그러나 ln -s doesnotexist exists; test -e exists || echo "does it really not exist?". 예를 들어 동일합니다 ln -s /var/spool/cron/crontabs/. exists(그리고 당신은 crontab 그룹의 루트 또는 구성원이 아닙니다).
Stéphane Chazelas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.