如何用mv覆盖目标文件?


154

我想移到父目录的子目录中有大量文件和目录。目标目录中已经有一些文件和目录需要覆盖。仅存在于目标中的文件应保持不变。我可以强迫mv这样做吗?(mv * ..)抱怨

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

我想念什么?


3
你试过了mv -f吗?
sakisk 2011年

我不知道为什么mv -f答案不正确。
Pedro Lobito

@PedroLobito:因为它不起作用?-f仅覆盖文件,但如果移动目标中存在且不为空的子目录,则该文件将不起作用。
EricSchaefer

Answers:


117

你必须将它们复制到目标,然后删除源,使用命令cp -r * ..之后rm -rf *

我认为您不能使用来“合并”目录mv


4
好吧,那不是我不想做的事,因为这将花费很长时间……还是谢谢。
EricSchaefer 2011年

12
大概mv是因为您在同一文件系统上,所以速度更快?如果cp -l用于创建硬链接而不是实际移动文件怎么办?
mattdm 2011年

6
您应该使用cp -a而不是cp -r来保留文件属性(时间戳,权限等)。
dotancohen 2014年

2
对于通过google到达这里的人来说,@ palswim的以下回答通过创建指向数据的新硬链接,然后删除旧链接来模拟mv的行为。简短的回答cp -rl source destination && rm -r source
威廉·埃弗里特

72

rsync可能是一个更好的选择。就像一样简单rsync -a subdir/ ./

我的测试树filenamecontents格式:

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

正在运行rsync

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

给出:

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

然后,要进行仿真mv,您可能想要删除源目录:

$ rm -r subdir/

给予:

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

如果这是错误的,您是否可以提供一个类似的示例(例如,使用该答案顶部附近的测试树)并获得所需的结果?


1
rsync副本。这个问题是关于搬家的。
吉尔斯

1
@吉尔斯:谢谢。我rm -r在末尾添加了使其与基本上相同mv
Mikel

3
当源和目标位于同一文件系统上时,复制然后删除不等同于mv。mv是原子的,保留inode编号(因此文件可以保持打开状态),并且无需花费时间和空间即可进行复制。
吉尔斯

5
@吉尔斯:我知道,但是目前的主要答案是cp -r; rm -r。我认为从这个意义上讲,rsync也值得一提。
Mikel

我已经用cp / rm做到了(很紧急)。确实花了很长时间。Gilles的脚本可能会快很多,但是他也来不及了。
EricSchaefer 2011年

47

rsync使用--remove-source-files参数复制后可以删除源。这应该是完成您想要的事情的便捷方法。

来自rsync man page

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

这确实是最好的答案。cp -r; rm由于缺少可用空间,我无法使用。相反,rsync --remove-source-files两者都将已用磁盘空间最小化,避免了复制完全相同的文件。
瓜卡2014年

20

您可以使用cp和进行此操作rm,但无需复制大量的数据(大概)是要避免传输数据。@mattdm在其评论中暗示了这一点,而对另一个问题的答案则对各种选项进行了更完整的讨论。

cp -rlf source destination
rm -r source

本质上,该命令的-l选项将cp创建到文件的硬链接,而不是将其数据复制到新文件。


1
我知道OP已经完成了提示问题的任务,但是希望这个答案将来可以对任何有此问题的人有所帮助。
palswim,2015年

这确实是他们需要的答案。我只是用60GB的成千上万个小型赛勒斯电子邮件文件完成了此操作,而这只花了21秒。
labradort 2015年

这也是我采用的方法-我只是cp -al source destination为了保留所有者信息和权限而对其进行了更改。
piit79,2015年

我认为要执行OP要求的操作,必须添加-f选项,否则如果文件存在,它将不会被覆盖。您可以确认还是我做错了什么?
das Keks,

@dasKeks:实际上,cp默认情况下会覆盖。该-f选项尝试rm在尝试重新复制之前删除文件(如中的),这可以在进程无法打开文件进行写入的情况下提供帮助,尽管有些人希望看到出现错误。我不知道这对OP是否重要,但是-f无论如何,我还是将标记添加到了答案中。
palswim

8

这是一个脚本,可将文件从下移动到下/path/to/source/root的相应路径/path/to/destination/root

  • 如果目录同时存在于源目录和目标目录中,则内容将以递归方式移动和合并。
  • 如果源中存在文件或目录,但目标中不存在,则将其移动。
  • 目标中已存在的任何文件或目录都将被留下。(特别是合并的目录留在了源代码中。这不容易解决。)

当心,未经测试的代码。

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
' {} \;

两个更正:你需要一个\;之前-o在第一线find指挥,你不应该逃避!if-它只是!\!
llhuii

2

该线程已经存在多年了,但在Google上仍然排名第一,所以我想添加另一种方法。我通常的操作方式是:将subdir内容打包到tarball中,将tarball移到父目录中,然后使用默认的--overwrite行为将其解压缩。这正是您要寻找的。之后,您可以删除您的子目录。

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

仅当您有压缩tar文件的额外空间时,此方法才有效。而且,您真的要在提取后保留临时tar文件吗?
Anthon

编辑代码以删除tmp文件。如今,在大多数情况下,空间已不是问题。#terabyteages
西蒙·克劳斯

0

如果您有足够的存储空间,则可以通过以下方式进行:

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

确保没有任何重要文件在文件末尾带有〜,但是如果有,则可以添加--suffix=whateveryouwant而不是默认文件。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.