如何将子目录(和文件)移动和覆盖到父目录?

Eri*_*fer 205 command-line shell files

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

mv: cannot move `xyz' to `../xyz': Directory not empty
Run Code Online (Sandbox Code Playgroud)

我错过了什么?

dog*_*ane 160

您必须将它们复制到目的地,然后使用cp -r * ..后跟的命令删除源rm -rf *。

我认为您不能使用mv.

  • 大概 `mv` 更快,因为你在同一个文件系统上?如果你使用 `cp -l` 来创建硬链接而不是实际移动文件怎么办? (13认同)
  • 嗯,这就是我不想做的,因为这将需要很长时间......无论如何,谢谢。 (8认同)
  • 对于通过谷歌迟到的人,@palswim 下面的答案通过创建新的数据硬链接然后删除旧链接来模拟 mv 的行为。简答`cp -rl source destination && rm -r source`。 (8认同)
  • 您应该使用 `cp -a` 而不是 `cp -r` 以保留文件属性(时间戳、权限等)。 (6认同)
  • 使用 `rm -rf` 时一定要小心,请务必在末尾指定文件夹名称,并且如果在脚本中,不要使用变量,您可能最终会运行 `rm -rf /`,这将“善良”中断你的服务器。 (5认同)

Mik*_*kel 86

rsync在这里可能是更好的选择。就这么简单rsync -a subdir/ ./。

我的测试树filename:contents格式:

./file1:root
./file2:root
./dir/file3:dir
./dir/file4:dir
./subdir/dir/file3:subdir
./subdir/file1:subdir
Run Code Online (Sandbox Code Playgroud)

运行rsync:

$ rsync -a -v subdir/ ./
sending incremental file list
./
file1
dir/
dir/file3
Run Code Online (Sandbox Code Playgroud)

给出:

./file1:subdir
./file2:root
./dir/file3:subdir
./dir/file4:dir
./subdir/dir/file3:subdir
./subdir/file1:subdir
Run Code Online (Sandbox Code Playgroud)

然后,为了模拟mv,您可能想要删除源目录:

$ rm -r subdir/
Run Code Online (Sandbox Code Playgroud)

给予:

./file1:subdir
./file2:parent
./dir/file3:subdir
./dir/file4:dir
Run Code Online (Sandbox Code Playgroud)

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

  • @Gilles:我意识到这一点,但目前领先的答案是`cp -r; rm -r`。我认为从这个意义上说,`rsync` 也值得一提。 (7认同)
  • 当源和目标位于同一文件系统上时,复制然后删除不等同于 mv。`mv` 是原子的,保留 inode 编号(因此文件可以保持打开状态),并且不需要时间和空间进行复制。 (4认同)
  • 这是完全错误的。rsync 正如您所展示的那样,它是增量副本。您需要添加 --delete, 选项。 (3认同)
  • rsync 副本。这个问题是关于搬家的。 (2认同)
  • @吉尔斯:谢谢。我在最后添加了 `rm -r` 以使其与 `mv` 基本相同。 (2认同)

小智 59

rsync 复制后可以删除源 --remove-source-files参数。

从rsync手册页:

--remove-source-files   sender removes synchronized files (non-dir)
Run Code Online (Sandbox Code Playgroud)

  • 这真的是最好的答案。我不能使用`cp -r; rm` 因为缺少可用空间。相反,`rsync --remove-source-files` 都最大限度地减少了使用的磁盘空间,避免了复制完全相同的文件。 (3认同)
  • 这会留下空文件夹。是否有一个标志可以删除空文件夹? (2认同)

pal*_*wim 34

您可以使用cp和来做到这一点rm,但无需复制您(大概)试图避免传输的大量数据。@mattdm提到这在他的评论,而另一个问题的答案具有的各种选项更完整的讨论。

cp -rlf source destination
rm -r source
Run Code Online (Sandbox Code Playgroud)

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

  • 我知道[OP已经完成了他的任务](http://unix.stackexchange.com/q/9899/13308#comment12812_9920)这引发了这个问题,但希望这个答案可以帮助任何人在未来解决这个问题。 (3认同)
  • 这也是我采取的路线 - 我只是将其更改为“cp -al source destination”以保留所有者信息和权限。 (2认同)

Gil*_*il' 9

这是一个将文件从下移动/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
' {} \;
Run Code Online (Sandbox Code Playgroud)