cp
대상 파일이 이미 존재하는 경우 (Linux의 GNU coreutils에서) 0이 아닌 값을 반환하는 방법이 있습니까?
아니면 이 기능을 제공하는 일반적으로 사용되는 다른 작은 유틸리티가 있습니까?
이는 쉘 스크립트에서 실수로 아무것도 잃지 않고 사용자 상호 작용 없이 파일을 자동으로 복사하는 데 유용합니다. 사본을 원본과 비교하면 비슷한 결과를 얻을 수 있지만 더 간단한 해결책이 있기를 바랍니다.
답변1
일부 cp
구현(GNU 포함 ) 에는 파일이 있는 경우 파일을 손상시키지 않는 cp
비표준 스위치가 있습니다 . -n
그러나 GNU는 cp
어쨌든 돌아옵니다.0
쉘 스크립트에서 if 문을 사용하여 파일 내용을 복사하기 전에 파일이 존재하는지 테스트할 수 있습니다.
if [ -e /path/to/file ]
then
exit 1
else
cp file /path/to/file
fi
또는 기능을 원하면 다음과 같이 사용할 수 있습니다.
function cpa(){
if [ -e "$2" ]
then
exit 1
else
/bin/cp "$1" "$2"
fi
}
답변2
다음 셸 조각은 대상이 존재하지 않는 경우에만 파일을 복사하고, 대상이 존재하는 경우 0이 아닌 상태를 반환합니다.
(set -C; : >"$target" && cp -- "$source" "$target")
이는 원자적이지 않습니다. $target
파기 시도 후 복사가 시작되기 전에 파일이 생성되면 덮어쓰게 됩니다. 게다가 cp
이는 원자적이지 않습니다. 다른 프로세스가 파일이 작성되는 것을 관찰할 수 있습니다. 그러나 모든 동시 작성자가 동일한 전략을 사용하는 경우에는 제대로 작동합니다.
다음의 보다 복잡한 코드 조각은 먼저 임시 복사본을 만든 다음 해당 위치로 이동합니다. 여전히 경쟁 조건이 있습니다. 실행 중이 아닌 관련 없는 프로그램이 개체 파일을 생성할 수 있는 작은 시간 창이 있습니다.
( set -C
tmp=$(mktemp -p "$(dirname -- "$target")")
cp -- '$source" "$tmp"
if : >"$target"; then
mv -i -- "$tmp" "$target"
else
rm -- "$tmp"
false
fi
)
답변3
h3rrmiller의 답변에 대한 내 의견을 확장하고 Gilles의 조각 패턴을 따르는 것은 임시 복사본을 만든 다음 제자리로 이동하는 또 다른 방법입니다. 나는 이 접근 방식이 경쟁 조건에 영향을 받지 않는다고 생각합니다. POSIX 사양의 일부가 아닌 -n
on 플래그가 필요합니다 . mv
그러나 널리 사용되는 것으로 보입니다. (GNU 구현과 BusyBox, FreeBSD, OS X에서 검증되었습니다.)
(
tmp=$(mktemp "${target}.XXXXXX") && # "mktemp -p" doesn't work on BSD
cp -- "$source" "$tmp" && # you may want to add -p flag
inode=$(ls -di "$tmp" | cut -d' ' -f1) && # see comment below
mv -n -- "$tmp" "$target" && # won't overwrite, but doesn't then exit non-0
if [ "$(ls -di "$target" | cut -d' ' -f1)" != "$inode" ]; then
rm -- "$tmp"; false
fi
)
stat -c'%i' "$tmp"
Linux에서는 다음을 사용하여 inode를 얻을 수 있습니다.그거 휴대용이 아니잖아.
또 다른 아이디어는 inode를 확인하는 대신 파일이 경로에 아직 존재하는지 확인하는 것입니다 $tmp
. mv -n ...
성공 하면 없어야 합니다. ( $tmp
손실을 확인하기 전에 다른 프로세스가 새로 생성되지 않은 경우.)
$target
효율성을 위해 루틴 시작 부분에 존재 여부 확인을 추가하는 것이 좋습니다. 존재한다는 사실을 알게 되면 복사본을 만들고 이동하려고 시도한 후 실패한 것을 확인하고 복사본을 삭제하는 대신 즉시 실패할 수 있습니다. 다음은 (간단한) 연습입니다.
답변4
다음을 수행할 수 있습니다.
(set -C && cat < /path/to/src > /path/to/dest)
cp
그러나 파일 내용( 일부 구현과 같은 권한, 소유권 또는 희소성 제외) 외에는 아무것도 복사하지 않습니다 .