Nếu tôi sử dụng mv
để di chuyển một thư mục gọi là "thư mục" sang một thư mục đã chứa "thư mục" thì chúng sẽ hợp nhất hay nó sẽ được thay thế?
Nếu tôi sử dụng mv
để di chuyển một thư mục gọi là "thư mục" sang một thư mục đã chứa "thư mục" thì chúng sẽ hợp nhất hay nó sẽ được thay thế?
Câu trả lời:
mv
không thể hợp nhất hoặc ghi đè các thư mục, nó sẽ thất bại với thông báo "mv: không thể di chuyển 'a' sang 'b': Thư mục không trống" , ngay cả khi bạn đang sử dụng --force
tùy chọn.
Bạn có thể làm việc xung quanh này sử dụng các công cụ khác (như rsync
, find
hoặc thậm chí cp
), nhưng bạn cần phải xem xét một cách cẩn thận những tác động:
rsync
có thể hợp nhất các nội dung của một thư mục vào một (lý tưởng với --remove-source-files
1 tùy chọn để xóa một cách an toàn chỉ những tập tin nguồn mà đã được chuyển giao thành công, và với tùy chọn thông thường cho phép / quyền sở hữu / thời gian bảo quản -a
nếu bạn muốn) rsync
's --link-dest=DIR
tùy chọn (để tạo liên kết cứng thay vì sao chép nội dung tập tin, nếu có thể) và --remove-source-files
để có được một ngữ nghĩa rất giống với một thường xuyên mv
. --link-dest
cần phải được cung cấp một đường dẫn tuyệt đối đến thư mục nguồn (hoặc một đường dẫn tương đối từ đích đến nguồn ). --link-dest
một cách ngoài ý muốn (mà có thể hoặc không có thể gây ra các biến chứng), đòi hỏi phải biết (hoặc xác định) đường dẫn tuyệt đối đến nguồn (như một đối số --link-dest
), và một lần nữa để lại một cấu trúc thư mục trống được làm sạch lên như mỗi 1 .find
để liên tục tái cấu trúc thư mục nguồn vào mục tiêu, sau đó cá nhân di chuyển các tập tin thực tế cp
có thể tạo liên kết cứng (chỉ cần đặt, gợi ý bổ sung cho cùng một tập tin hiện có), mà tạo ra một kết quả rất giống với một sáp nhập mv
(và rất IO-hiệu quả vì chỉ có con trỏ được tạo ra và không có dữ liệu thực tế phải được sao chép) Những cách giải quyết nào (nếu có) là phù hợp sẽ phụ thuộc rất nhiều vào trường hợp sử dụng cụ thể của bạn.
Như mọi khi, hãy suy nghĩ trước khi bạn thực hiện bất kỳ lệnh nào trong số này và có bản sao lưu.
1: Lưu ý rằng rsync --remove-source-files
sẽ không xóa bất kỳ thư mục nào, vì vậy bạn sẽ phải làm một cái gì đó như find -depth -type d -empty -delete
sau đó để thoát khỏi cây thư mục nguồn trống.
mv
triển khai được sử dụng bởi Debian - sự nhấn mạnh đang được thử , vì trang này không đề cập đến hành vi này ...
--delete
chỉ xóa các tệp trong thư mục đích không tồn tại trong thư mục nguồn.
-H
chức năng hoặc bạn có thể liên kết các tệp cứng ở đích bằng cách sử dụng --link-dest
. Xem trang người đàn ông trước khi sử dụng chúng, mặc dù.
rsync -av /source/ /destination/
(after checking)
rm -rf /source/
--remove-source-files
có lợi thế là chỉ xóa các tệp đã được chuyển thành công, vì vậy bạn có thể sử dụng find
để xóa các thư mục trống và sẽ được để lại mọi thứ không được chuyển mà không phải kiểm tra rsync
đầu ra.
Bạn có thể sử dụng -l
tùy chọn của lệnh cp , tạo ra các liên kết cứng của các tệp trên cùng một hệ thống tệp thay vì các bản sao dữ liệu đầy đủ. Lệnh sau sao chép thư mục source/folder
vào thư mục mẹ ( destination
) đã chứa thư mục có tên folder
.
cp -rl source/folder destination
rm -r source/folder
Bạn cũng có thể muốn sử dụng -P
( --no-dereference
- không hủy liên kết tượng trưng) hoặc -a
( --archive
- bảo toàn tất cả siêu dữ liệu, cũng bao gồm -P
tùy chọn), tùy thuộc vào nhu cầu của bạn.
cp
thay rsync
vì kể từ khi mọi hệ thống có cp
và mọi người đều quen thuộc với nó.
cp
với thời gian hoạt động của mv
.
-n
mv /fs1/file /fs2/
(trên các hệ thống tập tin) sẽ thực hiện một bản sao và sau đó xóa.
mv
sẽ hoạt động (miễn là thư mục tiêu chưa tồn tại) ngay cả khi không "hiệu quả" hoặc bất cứ điều gì bạn gọi nó, cp -rl
sẽ thất bại.
Tôi muốn giới thiệu bốn bước sau:
cd ${SOURCE};
find . -type d -exec mkdir -p ${DEST}/\{} \;
find . -type f -exec mv \{} ${DEST}/\{} \;
find . -type d -empty -delete
hoặc tốt hơn nữa, đây là một kịch bản thực hiện ngữ nghĩa tương tự như mv
:
#!/bin/bash
DEST="${@:${#@}}"
ABS_DEST="$(cd "$(dirname "$DEST")"; pwd)/$(basename "$DEST")"
for SRC in ${@:1:$((${#@} -1))}; do (
cd "$SRC";
find . -type d -exec mkdir -p "${ABS_DEST}"/\{} \;
find . -type f -exec mv \{} "${ABS_DEST}"/\{} \;
find . -type d -empty -delete
) done
rsync -u
(chỉ cập nhật nếu mới hơn), mv
(ít nhất là trong một số phiên bản) cũng có thể thực hiện -u
tùy chọn này. Tuy nhiên, trong trường hợp đó, bạn có thể muốn xóa các thư mục nguồn không trống cũng như các thư mục trống, để bao quát các trường hợp trong đó các tệp trong cây nguồn không mới hơn. @schuess: Có vẻ như có thể có nhiều đối số SOURCE, nếu bạn cần điều đó.
Đây là một cách sẽ hợp nhất các thư mục. Nó nhanh hơn nhiều so với rsync vì nó chỉ đổi tên các tệp thay vì sao chép chúng và sau đó xóa chúng.
cd source; find -type f -print0 | xargs -0 -n 1 -I {} mv '{}' 'dest/{}'
dest
đã là một thư mục có cùng tên như trong source
. Và các tập tin sẽ được chuyển đến một dest
, trong đó source
. Lệnh không làm gì hơnmv source/* source/dest/.
Một cách để thực hiện điều này sẽ là sử dụng:
mv folder/* directory/folder/
rmdir folder
Miễn là không có hai tệp nào có cùng tên folder
và directory/folder
bạn sẽ đạt được cùng một kết quả, tức là hợp nhất.
rm folder
làm việc?
rm folder -fR
luôn làm việc cho tôi
Đối với các bản sao thuần túy nhất, tôi sử dụng phương pháp sao chép khối B (-) B.
ví dụ, từ bên trong đường dẫn nguồn ('cd' nếu cần):
tar cBf - <sourcefolder> | (cd /your/target/folder ; tar xBf -)
điều này tạo ra một bản sao chính xác của cây nguồn, VỚI chủ sở hữu và các quyền còn nguyên vẹn. Và nếu thư mục đích tồn tại, dữ liệu sẽ được hợp nhất. Chỉ các tệp đã tồn tại sẽ được ghi đè.
Thí dụ:
$ cd /data1/home
$ tar cBf - jdoe | (cd /data2/home ; tar xBf -)
Khi hành động sao chép thành công, bạn có thể xóa nguồn ( rm -rf <source>
). Tất nhiên đây không phải là một động thái chính xác: dữ liệu sẽ được sao chép, cho đến khi bạn xóa nguồn.
Như tùy chọn, bạn có thể dài dòng (hiển thị trên màn hình tệp đang được sao chép), với -v: tar cBvf -
c
: tạo nênB
: đọc toàn bộ khối (đối với đọc ống)v
: dài dòngf
: tập tin để viếtx
: trích xuất-
: stdout / stdinsourcefolder
cũng có thể là *
(cho bất cứ điều gì trong thư mục hiện tại)
f -
tar thường không cần thiết - mặc định là đọc từ stdin / write sang stdout.
Đây là một kịch bản làm việc cho tôi. Tôi thích mv hơn rsync, vì vậy tôi sử dụng các giải pháp của Jewel và Jonathan Mayer.
#!/bin/bash
# usage source1 .. sourceN dest
length=$(($#-1))
sources=${@:1:$length}
DEST=$(readlink -f ${!#})
for SRC in $sources; do
pushd $SRC;
find . -type d -exec mkdir -p ${DEST}/{} \;
find . -type f -exec mv {} ${DEST}/{} \;
find . -type d -empty -delete
popd
done
Nó không phải là một ý tưởng tốt để sử dụng các lệnh như cp hoặc rsync. Đối với các tệp lớn, sẽ mất nhiều thời gian. mv nhanh hơn nhiều vì nó chỉ cập nhật các nút mà không sao chép các tệp vật lý. Một lựa chọn tốt hơn là sử dụng trình quản lý tệp của hệ điều hành của bạn. Đối với Opensuse, có một trình quản lý tệp có tên Konquerer. Nó có thể di chuyển các tập tin mà không thực sự sao chép chúng. Nó có chức năng "cắt và dán" như trong Windows. Chỉ cần chọn tất cả các thư mục con trong thư mục A. Nhấp chuột phải và "di chuyển vào" thư mục B có thể chứa các thư mục con có cùng tên. Nó sẽ hợp nhất chúng. Ngoài ra còn có các tùy chọn cho dù bạn muốn ghi đè hoặc đổi tên các tệp có cùng tên.
mv
được sử dụng.
Giải pháp Python
Vì tôi không thể tìm thấy một giải pháp có sẵn thỏa đáng, tôi quyết định tạo một kịch bản Python nhanh để đạt được nó.
Đặc biệt, phương pháp này hiệu quả vì nó chỉ đi theo cây tệp nguồn một lần từ dưới lên.
Nó cũng sẽ cho phép bạn nhanh chóng điều chỉnh những thứ như xử lý ghi đè tập tin theo ý thích của bạn.
Sử dụng:
move-merge-dirs src/ dest/
sẽ di chuyển tất cả nội dung src/*
vào dest/
và src/
sẽ biến mất.
di chuyển hợp nhất-dirs
#!/usr/bin/env python3
import argparse
import os
def move_merge_dirs(source_root, dest_root):
for path, dirs, files in os.walk(source_root, topdown=False):
dest_dir = os.path.join(
dest_root,
os.path.relpath(path, source_root)
)
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
for filename in files:
os.rename(
os.path.join(path, filename),
os.path.join(dest_dir, filename)
)
for dirname in dirs:
os.rmdir(os.path.join(path, dirname))
os.rmdir(source_root)
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='Move merge src/* into dest. Overwrite existing files.'
)
parser.add_argument('src_dir')
parser.add_argument('dest_dir')
args = parser.parse_args()
move_merge_dirs(args.src_dir, args.dest_dir)
Đây là lệnh để di chuyển tệp và thư mục đến đích khác:
$ mv /source/path/folder /target/destination/
Ghi : mv
lệnh sẽ không hoạt động nếu thư mục được được sáp nhập (tức là một thư mục khác có cùng tên đã tồn tại trong đích) và một nơi lý là không có sản phẩm nào .
mv: không thể di chuyển '/ source / path / thư mục' sang '/ target / Destination / thư mục': Thư mục không trống
Nếu thư mục đích trống, lệnh trên sẽ hoạt động tốt.
Vì vậy, để hợp nhất cả hai thư mục trong mọi trường hợp,
Hoặc thực hiện theo 2 lệnh:
$ cp -rf /source/path/folder /target/destination/
$ rm -rf /source/path/folder
Hoặc kết hợp cả hai như một lệnh một lần:
$ cp -rf /source/path/folder /target/destination/ && rm -rf /source/path/folder
mv = di chuyển
cp = sao chép
rm = xóa-r cho thư mục (thư mục)
-f thực thi lực lượng
mv
. Câu trả lời này sẽ tốt hơn với một sự thật rộng lớn hơn. Linux, BSD và Unix "thực" hoặc tài liệu tham khảo từ POSIX hoặc SUS.