Làm thế nào để ngăn cp hợp nhất hai thư mục có tên giống hệt nhau?


7

Tôi có hai thư mục có tên giống hệt nhau:

$ ls mydir
file1 file2

$ ls other/mydir
file3 file4

Nếu tôi sao chép mydirvào other, hai mydirs được hợp nhất:

$ cp -r mydir other

$ ls other/mydir
file1 file2 file3 file4

Trường hợp trong trang người đàn ông (hoặc thông tin) cho cpbiết nó làm điều này theo mặc định?

Điều tương tự xảy ra nếu tôi sử dụng cp -rn mydir other.

Tôi thích nó hơn nếu được cphỏi liệu tôi có muốn hợp nhất hai mydirs không; do đó nếu tôi sao chép mydirđể otherkhi quên rằng đã có một khác nhau mydirtrong other, tôi có thể hủy bỏ các hoạt động. Điều này có thể không?


Trang man của cp nói rằng cờ -n tránh ghi đè các tập tin hiện có, nó không nói gì về các thư mục. Giống như cp, nhiều lệnh khác có cờ để tránh ghi đè lên các tệp hiện có. Ví dụ về các lệnh như vậy là tar (-k) và rsync (--ignore-tồn tại). Thật không may, tôi biết không có công cụ dòng lệnh nào tránh được việc hợp nhất các thư mục khi sao chép đệ quy.
Henrik Carlqvist

2
Không chắc chắn nếu đây là những gì bạn đang tìm kiếm nhưng bạn có thể thêm một chút kiểm tra trước khi chạy cplệnh. if [ ! -d other/mydir] ; then; cp -r mydir other; else; echo "Directory already exists at destination"; fi
Munir

1
@munircontractor, tôi nghĩ đó thực sự là giải pháp tốt nhất. Nó có thể được làm sạch một chút nhưng sự thật là câu trả lời cốt lõi cho câu hỏi tiêu đề chính xác là: "Bạn không thể ngăn chặn cpviệc đó trừ khi bạn kiểm tra trước, vì vậy hãy chắc chắn rằng bạn kiểm tra trước."
tự đại diện

@munircontractor - Cảm ơn bạn vì một giải pháp đơn giản. Vấn đề duy nhất là việc kiểm tra thủ công dễ dàng hơn lsthay vì chỉnh sửa tập lệnh này mỗi lần.
EmmaV

Câu trả lời:


5

Tôi không thấy tài liệu này trong tài liệu hướng dẫn sử dụng lõi GNU. Nó được chỉ định bởi POSIX :

2. Nếu source_file thuộc loại thư mục, các bước sau sẽ được thực hiện:

[ các bước snip không áp dụng trong chế độ đệ quy khi tệp đích là một thư mục hiện có]

    f. Các tập tin trong thư mục source_file sẽ được sao chép vào thư mục Dest_file [ Hoài ]

cp -rnkhông giúp được gì vì -ntùy chọn chỉ nói rằng không ghi đè lên, nhưng việc hợp nhất các thư mục không ghi đè lên bất cứ điều gì.

Tôi không thấy bất kỳ lựa chọn nào rsynchoặc paxsẽ giúp bạn.

Bạn có thể có được hành vi này với một gói bao quanh cp. Phân tích các tùy chọn dòng lệnh là khó khăn mặc dù. Mã chưa được kiểm tra. Vấn đề đã biết: điều này không hỗ trợ các tùy chọn viết tắt dài.

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 "$@"
}

Đợi đã, cái gì shift args?
Arthur2e5

@ Arthur2e5 Xin lỗi, zshism. Tôi đã sửa lỗi đó và một vài lỗi khác.
Gilles 'SO- ngừng trở nên xấu xa'

Cảm ơn bạn. Tôi nghĩ rằng tôi bắt buộc phải chấp nhận điều này vì số lượng lớn nỗ lực mà bạn rõ ràng đã bỏ ra.
EmmaV

1

Bạn có thể tạo tập lệnh bao bọc để sao chép thư mục (cpDirs) sẽ kiểm tra xem có bất kỳ sự hợp nhất nào xảy ra không:

#!/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

0
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-oktác phẩm nguyên thủy như -execngoại trừ việc nó nhắc nhở người đầu tiên stderr của nó với một mô tả của lệnh đó là về để chạy và chờ đợi một phản ứng khẳng định hay phủ (như yhay n) sau đó Enter. findKịch bản trên sẽ nhắc xác nhận nếu một thư mục /src/pathcũng tồn tại /tgt/pathtrước khi sao chép nó, nhưng tất cả các tệp tìm thấy /src/pathđược sao chép mà không cần nhắc.

(bạn sẽ phải xóa echos để làm cho nó làm bất cứ điều gì hơn là giả vờ làm việc)

Một findtập lệnh khác gọi shell cho các thư mục cấp đầu tiên bên dưới /src/pathcó thể trông như sau:

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 {} +
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.