동일한 이름을 가진 두 개의 디렉토리가 있습니다.
$ ls mydir
file1 file2
$ ls other/mydir
file3 file4
mydir
에 복사하면 other
두 개의 mydir
가 병합됩니다.
$ cp -r mydir other
$ ls other/mydir
file1 file2 file3 file4
매뉴얼(또는 정보) 페이지 어디에 cp
이것이 기본적으로 수행된다고 나와 있습니까?
을 사용해도 같은 일이 발생합니다 cp -rn mydir other
.
cp
나는 두 개를 병합할지 묻는 질문을 받는 것을 선호합니다. mydir
그러면 복사 mydir
한 other
후 다른 항목이 mydir
이미 존재한다는 사실을 잊어버린 경우 other
작업을 중단할 수 있습니다. 가능합니까?
답변1
GNU coreutils 매뉴얼에서는 이것을 볼 수 없습니다. 다음과 같이 지정됩니다.POSIX:
2. 만약에소스 파일디렉터리 유형인 경우 다음 단계를 수행해야 합니다.
[전단대상 파일이 기존 디렉터리인 경우 재귀 모드에 적용되지 않는 단계]
에프. 디렉토리의 파일소스 파일이 디렉토리에 복사해야 합니다대상 파일[…]
cp -rn
옵션에는 "덮어쓰지 않음"만 표시되어 있으므로 도움이 되지 않지만 -n
디렉터리를 병합해도 아무 것도 덮어쓰지 않습니다.
rsync
어떤 옵션 이나 pax
도움도 볼 수 없습니다 .
래퍼를 통해 이 동작을 얻을 수 있습니다 cp
. 그러나 명령줄 옵션을 구문 분석하는 것은 지루한 작업입니다. 테스트되지 않은 코드. 알려진 문제: 이는 축약된 긴 옵션을 지원하지 않습니다.
function cp {
typeset source target=
typeset -a args sources
args=("$@") sources=()
while [[ $# -ne 0 ]]; do
case "$1" in
--target|-t) target=$2; shift args;;
--target=*) target=${1#*=};;
-t?*) target=${1#??};;
--no-preserve|--suffix|-S) shift;;
--) break;;
-|[^-]*) if [ -n "$POSIXLY_CORRECT" ]; then break; else sources+=($1); fi;;
esac
shift
done
sources+=("$@")
if [[ -z $target && ${#sources[@]} -ne 0 ]]; then
target=${sources[-1]}
unset sources[-1]
fi
for source in "${sources[@]}"; do
source=${source%"${source##*[^/]}"}
if [ -e "$target/${source##*/}" ]; then
echo >&2 "Refusing to copy $source to $target/${source##*/} because the target already exists"
return 1
fi
done
command cp "$@"
}
답변2
병합이 발생하는지 확인하는 디렉터리 복사용 래퍼 스크립트(cpDirs)를 만들 수 있습니다.
#!/bin/sh
test -d "$1" && test -d "$2" || { >&2 echo "Not directories"; exit 1; }
conflicts="`for d in "$1" "$2"; do (cd "$d"; find -mindepth 1 -type d); done |
sort |uniq -d`"
if [ -n "$conflicts" ]; then
>&2 printf 'The following directories would be merged:\n%s\n' "$conflicts"
exit 1
else
cp -r "$@"
fi
답변3
cd /src/path &&
find . -type d ! -name . -prune \
\( -exec test -e /tgt/path/{} \; \
\( -ok echo cp -rt /tgt/path {} \; \
-o -exec printf 'not copied:\t%s\n' {} \; \
\) \) -o ! -name . -exec echo cp -rt /tgt/path {} +
find
원본 -ok
도 비슷하게 작동합니다 -exec
. 단, 먼저 실행할 명령에 대한 설명과 함께 stderr를 프롬프트하고 긍정적이거나 부정적인 응답을 기다립니다.(예: y
또는 n
)그런 다음 입력하십시오. 위 find
스크립트는 디렉토리가 존재하는지 확인하라는 메시지를 표시합니다./src/path
에도 존재합니다/tgt/path
복사하기 전에 발견된 모든 파일이/src/path
메시지를 표시하지 않고 복사합니다.
echo
( 하지만 작동하는 척하는 것 외에 다른 작업을 수행하려면 s를 제거해야 합니다 .)
또 다른 find
스크립트는 한 수준 아래 디렉터리의 셸을 호출합니다./src/path
다음과 같이 보일 수 있습니다:
cd /src/path &&
find . ! -name . -prune -exec sh -c '
[ -t 0 ] &&
trap "stty $(stty -g;stty -icanon)
trap - 0 1 2; exit" 0 1 2
for f
do [ -e "$0/$f" ] &&
case $(printf "%b:\n%s\n" >&2 \
\\nsource "$(ls -ld -- "$PWD/$f")" \
\\ntarget "$(ls -ld -- "$0/$f")" \
"copy source over target?(\"y\"es|a\"no\"ther key): \c"
dd count=1 2>/dev/null
echo >&2) in ([yY]) ! :
esac|| set -- "$@" "$f"; shift
done; cp -r "$@" "$0"
' /tgt/path {} +