如何在 Linux 中将目录复制到现有目录?
概述
复制文件是使用 Linux Shell 执行的最常见操作之一。我们通常使用 cp(复制)命令来实现此目的。
我们将讨论如何递归地将文件夹移动到另一个位置(包括覆盖或不覆盖)。
问题介绍
首先,我们需要了解"将文件夹复制到另一个位置"在本题中的含义。
一个好的例子可以帮助您更好地理解。
$ tree -a . ├── src │ ├── .hidden.file │ ├── srcFile.txt │ └── subSrc │ └── subSrcFile.txt └── target └── originalTarget.file
3 个目录,4 个文件
如上图所示,src 文件夹下有两个目录。其中包含一些源代码文件和一个子文件夹。此外,还有一个隐藏文件。
现在我们需要将源文件夹复制到目标文件夹。
我们希望目标文件夹与源文件夹完全相同。
├── src │ ├── .hidden.file │ ├── srcFile.txt │ └── subSrc │ └── subSrcFile.txt └── target ├── .hidden.file ├── srcFile.txt └── subSrc └── subSrcFile.txt
但是,如果我们只是将源文件夹的内容复制到目标文件夹,我们希望 src 下的所有内容都递归移动到目标文件夹。我们还希望目标文件夹下的原始文件保持不变。
├── src │ ├── .hidden.file │ ├── srcFile.txt │ └── subSrc │ └── subSrcFile.txt └── target ├── .hidden.file ├── originalTarget.file ├── srcFile.txt └── subSrc └── subSrcFile.txt
由于目标目录已经存在,我们不能直接使用 cp -r src target 方法来执行此任务。相反,我们需要先在目标目录中创建一个名为 src 的新目录。然后,我们可以将文件从 src 移动到新创建的 src 目录中。
之后,我们将讨论如何通过两种不同的方法实现我们的目标 -
使用 cp 命令
使用 rsync 命令
使用 cp 命令
我们首先来看看如何使用 cp 命令来解决这个问题,因为这很常见。
cp 命令不覆盖目标目录
如果源文件夹不为空,我们不能简单地使用 cp 命令将源文件夹的内容复制到目标文件夹。
但是,cp 命令有一个 -i 选项,它会将源文件视为常规文件,而不是文件夹。
如果我们使用 −rT 选项,那么 cp 命令将递归遍历源文件夹的内容,并在目标文件夹中创建它们的副本。
$ cp -rT src target $ tree -a . ├── src │ ├── .hidden.file │ ├── srcFile.txt │ └── subSrc │ └── subSrcFile.txt └── target ├── .hidden.file ├── originalTarget.file ├── srcFile.txt └── subSrc └── subSrcFile.txt
4 个目录,7 个文件
tree 的 -a 选项告诉我们,我们将源目录中的所有内容复制到目标目录中。但是,复制操作并不包含源目录。所以,我们完成了!
Bash 通配符技巧
我们已经通过使用带有 -rT 选项的 cp 命令解决了这个问题。
我们可以通过将 src 中的所有内容复制到 target 来解决这个问题。因此,我们可以这样写:cp -r src/* target。
我们可以通过将 src 中的所有内容复制到 target 来解决这个问题。因此,我们可以这样写:cp -r src/* target。
$ cp -r src/* target $ tree -a . ├── src │ ├── .hidden.file │ ├── srcFile.txt │ └── subSrc │ └── subSrcFile.txt └── target ├── originalTarget.file ├── srcFile.txt └── subSrc └── subSrcFile.txt
4 个目录,6 个文件
如树状图所示,src 下的大多数文件都已成功传输到目标文件夹,.dot 文件除外。这是因为使用"globstar"选项后,shell 会忽略任何以句点(".")开头的文件名。
有两种方法可以解决这个问题。一种方法是修改全局设置,使通配符包含 .dot 文件。您可以使用 shopt -s dotglob 命令来实现。
$ ( shopt -s dotglob; cp -r src/* target ) $ tree -a target target ├── .hidden.file ├── originalTarget.file ├── srcFile.txt └── subSrc └── subSrcFile.txt
1 directory, 4 files
$ shopt dotglob
dotglob off
从上面的输出中我们可以看到,点文件也已成功创建。此外,我们将 shoptcp 命令与 cp 命令一起用括号 (…) 括起来,这样它们就可以在子 shell 中运行,因为我们希望 shoptcp 命令只影响单个 cp 命令。
命令执行后,当我们检查通配符选项时,它们仍然处于禁用状态。
更改 bash 的默认行为很容易。但是,如果您自己编写脚本,这可能会带来不便。尤其是在您想避免意外后果的情况下。
您还可以使用"src/."而不是"src/*"将 .dotfiles 添加到源代码控制系统中。
让我们看看它是否按预期工作。
$ cp -r src/. target $ tree -a target target ├── .hidden.file ├── originalTarget.file ├── srcFile.txt └── subSrc └── subSrcFile.txt
1 directory, 4 files
cp 并覆盖目标目录
如果我们想用目标文件夹的内容替换源文件夹的内容,那么使用 -R 选项比 -O 选项更简单。因此,我们先删除目标文件夹,然后运行 cp -r 命令。
$ rm -r target && cp -r src target $ tree -a . ├── src │ ├── .hidden.file │ ├── srcFile.txt │ └── subSrc │ └── subSrcFile.txt └── target ├── .hidden.file ├── srcFile.txt └── subSrc └── subSrcFile.txt
4 个目录,6 个文件
使用 rsync 命令
rsync 是解决此问题的实用工具。
不覆盖目标目录的 rsync
我们可以使用两个 rsync 命令行来递归复制目录 -
rsync -a source target:将源目录的内容复制到目标目录
rsync -a src/ target-将 src 目录的内容复制到目标目录
上面两个命令几乎完全相同。以斜杠开头的那个正是我们要找的。p>
让我们在我们的示例中测试一下 -
$ rsync -a src/ target $ tree -a . ├── src │ ├── .hidden.file │ ├── srcFile.txt │ └── subSrc │ └── subSrcFile.txt └── target ├── .hidden.file ├── originalTarget.file ├── srcFile.txt └── subSrc └── subSrcFile.txt
4 个目录,7 个文件
树的结果表明该命令解决了我们的问题。
rysnc 并覆盖目标目录
我们已经了解到,可以结合使用两个命令行"sudo rmdir /path/to/folder && sudo cp -r /source/folder /path/to/destination"来解决问题。
使用 rsync,我们可以一次性完成所有操作 -
$ rsync -a --delete src/ target $ tree -a . ├── src │ ├── .hidden.file │ ├── srcFile.txt │ └── subSrc │ └── subSrcFile.txt └── target ├── .hidden.file ├── srcFile.txt └── subSrc └── subSrcFile.txt
4 个目录,6 个文件
执行 rsync 命令后,目标和源都包含相同的内容。因此,我们找到了原始问题的替代解决方案。
此解决方案的秘诀在于 -delete 开关。
-delete 选项指示 rsync 从 target/ 中删除任何在 source/ 中不存在的文件,以确保传输结束时源和目标文件完全相同。
结论
我们讨论了如何递归地将一个文件夹移动到另一个文件夹中(包括覆盖和不覆盖)。
我们学习了两种解决问题的方法:使用常见的 cp(复制)和 rsync 命令。
我们讨论了 bash 的 dotglob 设置及其如何影响通配符行为。
相关文章
有用资源
linux 参考教程 - 该教程包含有关 linux 的更多信息:https://www.cainiaomax.com/linux/

