Làm thế nào để ghi đè tập tin mục tiêu với mv?


155

Tôi có rất nhiều tập tin và thư mục trong thư mục con tôi muốn chuyển đến thư mục mẹ. Đã có một số tệp và thư mục trong thư mục đích cần được ghi đè. Các tập tin chỉ hiện diện trong mục tiêu nên được giữ nguyên. Tôi có thể buộc mvphải làm điều đó? Nó ( mv * ..) phàn nàn

mv: cannot move `xyz' to `../xyz': Directory not empty

Tôi đang thiếu gì?


3
Bạn đã thử mv -fchưa
sakisk

Tôi tự hỏi tại sao mv -fkhông trả lời đúng.
Pedro lobito

@PedroLobito: Vì nó không hoạt động? -f chỉ ghi đè lên các tệp, nhưng không hoạt động nếu bạn di chuyển các thư mục con tồn tại ở đích và không trống.
EricSchaefer

Câu trả lời:


118

Bạn sẽ phải sao chép chúng đến đích và sau đó xóa nguồn, sử dụng các lệnh cp -r * ..theo sau rm -rf *.

Tôi không nghĩ rằng bạn có thể "hợp nhất" các thư mục bằng cách sử dụng mv.


4
Chà, đó là điều tôi không muốn làm, vì sẽ mất nhiều thời gian ... Dù sao cũng cảm ơn.
EricSchaefer

12
Có lẽ mvlà nhanh hơn bởi vì bạn trên cùng một hệ thống tập tin? Điều gì nếu bạn sử dụng cp -lđể tạo liên kết cứng thay vì thực sự di chuyển các tập tin?
mattdm

6
Bạn nên sử dụng cp -athay vì cp -rđể bảo toàn các thuộc tính tệp (dấu thời gian, quyền, v.v.).
dotancohen

3
Đối với những người đến đây muộn thông qua google, câu trả lời dưới đây của @palswim mô phỏng hành vi của mv bằng cách tạo các liên kết cứng mới đến dữ liệu và sau đó xóa các liên kết cũ. Câu trả lời ngắn gọn cp -rl source destination && rm -r source.
William Everett

72

rsynccó lẽ sẽ là một lựa chọn tốt hơn ở đây Nó đơn giản như rsync -a subdir/ ./.

Cây thử nghiệm của tôi ở filename: contentsđịnh dạng:

./file1:root
./file2:root
./dir/file3:dir
./dir/file4:dir
./subdir/dir/file3:subdir
./subdir/file1:subdir

Chạy rsync:

$ rsync -a -v subdir/ ./
sending incremental file list
./
file1
dir/
dir/file3

Cung cấp:

./file1:subdir
./file2:root
./dir/file3:subdir
./dir/file4:dir
./subdir/dir/file3:subdir
./subdir/file1:subdir

Và sau đó, để mô phỏng mv, có lẽ bạn muốn xóa thư mục nguồn:

$ rm -r subdir/

Tặng:

./file1:subdir
./file2:parent
./dir/file3:subdir
./dir/file4:dir

Nếu điều này là sai, bạn có thể vui lòng cung cấp một ví dụ tương tự (ví dụ: sử dụng cây thử nghiệm của tôi từ gần đầu câu trả lời này) với kết quả mong muốn không?


1
bản sao rsync. Câu hỏi này là về việc di chuyển.
Gilles

1
@Gilles: Cảm ơn. Tôi đã thêm rm -rvào cuối để làm cho nó về cơ bản giống như mv.
Mikel

3
copy-then-xóa không tương đương với mv khi nguồn và đích nằm trên cùng một hệ thống tập tin. mvlà nguyên tử, bảo toàn số inode (vì vậy tệp có thể vẫn mở) và không mất thời gian và không gian để tạo bản sao.
Gilles

5
@Gilles: Tôi nhận ra điều đó, nhưng hiện tại câu trả lời hàng đầu là cp -r; rm -r. Tôi nghĩ theo nghĩa đó, rsynccũng đáng được đề cập.
Mikel

Tôi đã làm điều đó với cp / rm (nó là khẩn cấp). Nó thực sự mất một thời gian dài. Kịch bản Gilles có lẽ sẽ nhanh hơn rất nhiều, nhưng anh cũng đã quá muộn.
EricSchaefer

47

rsynccó thể xóa nguồn sau khi sao chép với --remove-source-filestham số. Đây phải là một cách thuận tiện để làm những gì bạn muốn.

Từ rsync man page:

        --remove-source-files   sender removes synchronized files (non-dir)

Đây thực sự là câu trả lời tốt nhất. Tôi không thể sử dụng cp -r; rmvì thiếu không gian trống. Thay vào đó, rsync --remove-source-filescả hai không gian đĩa được sử dụng tối thiểu hóa đều tránh sao chép trên cùng một tệp.
guaka

20

Bạn có thể làm điều này với cprm, nhưng không sao chép lượng dữ liệu khổng lồ mà bạn (có lẽ) đang cố gắng tránh chuyển. @mattdm đã ám chỉ điều này trong bình luận của anh ấy , và một câu trả lời cho một câu hỏi khác có một cuộc thảo luận đầy đủ hơn về các lựa chọn khác nhau.

cp -rlf source destination
rm -r source

Về cơ bản, -ltùy chọn cho cplệnh tạo các liên kết cứng đến các tệp thay vì sao chép dữ liệu của chúng sang các tệp mới.


1
Tôi biết OP đã hoàn thành nhiệm vụ của mình , điều này đã đặt ra câu hỏi, nhưng hy vọng câu trả lời này có thể giúp ích cho bất kỳ ai có vấn đề này trong tương lai.
palswim

Đây thực sự là câu trả lời họ cần. Tôi vừa làm điều này với 60GB của hàng ngàn tệp email cyrus nhỏ và chỉ mất 21 giây.
labradort

Đây cũng là con đường tôi đã đi - tôi chỉ thay đổi nó cp -al source destinationđể giữ thông tin và quyền của chủ sở hữu.
piit79

Tôi nghĩ để thực sự làm những gì OP yêu cầu bạn phải thêm tùy chọn -f nếu không nó sẽ không ghi đè nếu tệp tồn tại. Bạn có thể xác nhận rằng tôi đang làm gì đó sai?
das Keks

@dasKeks: Trên thực tế, cpghi đè theo mặc định. Các -ftùy chọn cố gắng để loại bỏ các tập tin (như trong rm) trước khi cố gắng sao chép một lần nữa, có thể giúp đỡ nếu quá trình này không thể mở tập tin để viết, mặc dù một số người muốn để thấy rằng đã có lỗi khi thay thế. Tôi không biết nó có quan trọng với OP không, nhưng dù sao tôi cũng đã thêm -fcờ vào câu trả lời của mình.
palswim

8

Đây là một tập lệnh di chuyển các tập tin từ bên dưới /path/to/source/rootđến đường dẫn tương ứng bên dưới /path/to/destination/root.

  • Nếu một thư mục tồn tại trong cả nguồn và đích, nội dung sẽ được di chuyển và hợp nhất theo cách đệ quy.
  • Nếu một tập tin hoặc thư mục tồn tại trong nguồn nhưng không ở đích, nó sẽ được di chuyển.
  • Bất kỳ tập tin hoặc thư mục đã tồn tại ở đích được để lại. (Đặc biệt các thư mục được hợp nhất được để lại trong nguồn. Điều này không dễ sửa.)

Cẩn thận, mã chưa được kiểm tra.

export dest='/path/to/destination/root'
cd /path/to/source/root
find . -type d \( -exec sh -c '[ -d "$dest/$0" ]' \; -o \
                  -exec sh -c 'mv "$0" "$dest/$0"' {} \; -prune \) \
    -o -exec sh -c '
        if ! [ -e "$dest/$0" ]; then
          mv -f "$0" "$dest/$0"
        fi
' {} \;

Hai điều chỉnh: bạn cần một \;trước -otrên dòng đầu tiên của findlệnh, và bạn không nên trốn !trong if- nó chỉ là !, không\!
llhuii

2

Chủ đề này đã tồn tại nhiều năm và vẫn đứng thứ 1 trên google vì vậy tôi muốn thêm một phương pháp khác. Làm thế nào tôi thường làm điều này: đóng gói nội dung của thư mục con vào một tarball, di chuyển tarball lên thư mục cha và sau đó giải nén nó với hành vi --overwrite mặc định. Điều này thực hiện chính xác những gì bạn đang tìm kiếm. Sau đó, bạn có thể loại bỏ subir của bạn.

cd xyz
tar -cvzpf tmp.tar.gz *
mv tmp.tar.gz ../tmp.tar.gz
cd ..
tar -xvzpf tmp.tar.gz
rm -rf xyz
rm -f tmp.tar.gz

Điều này chỉ hoạt động nếu bạn có thêm không gian cho tệp tar nén. Và bạn có thực sự muốn giữ tập tin tar tạm thời xung quanh sau khi giải nén không?
Anthon

Mã chỉnh sửa để loại bỏ tập tin tmp. Ngày nay, không gian không phải là vấn đề trong hầu hết các trường hợp. #terabyteages
Simon Kraus

0

Nếu bạn có đủ dung lượng, bạn có thể thực hiện theo cách sau:

mv -bfv directory_1/* directory_2/ # all duplicate source files/directories 
                                   # will have ~ appended to them
find -name "*~" -delete            # will recursively find and delete all files 
                                   # with ~ on the end

Đảm bảo không có bất kỳ tệp quan trọng nào có dấu ~ ở cuối chúng, nhưng nếu có, bạn có thể thêm --suffix=whateveryouwantthay vì mặc định.

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.