本文将揭示一些与使用相关的非显而易见的事情 cp
复制时,以及允许您正确复制大量文件而不会跳过或崩溃的方法。
假设我们需要将 /source 文件夹中的所有内容复制到 /target 文件夹。
第一个想到的是:
cp /source/* /target
让我们立即将此命令更正为:
cp -a /source/* /target
关键 -a
将添加所有属性、权限的复制并添加递归。 当不需要精确复制权利时,密钥就足够了 -r
.
复制后,我们会发现并非所有文件都被复制了 - 以点开头的文件,例如:
.profile
.local
.mc
等等。
为什么会这样?
因为通配符是由 shell 处理的(bash
在典型情况下)。 默认情况下,bash 将忽略所有以点开头的文件,因为它将它们视为隐藏文件。 为了避免这种行为,我们必须改变行为 bash
使用命令:
shopt -s dotglob
为了确保此行为更改在重新启动后仍然存在,您可以使用此命令在文件夹中创建一个通配符.sh 文件 /etc/profile.d
(也许您的发行版有不同的文件夹)。
如果源目录中没有文件,那么 shell 将无法替换星号的任何内容,并且复制也会失败并出现错误。 针对这种情况有一些选择 failglob
и nullglob
。 我们需要设置 failglob
,这将阻止命令被执行。 nullglob
将不起作用,因为它将未找到匹配项的带有通配符的字符串转换为空字符串(零长度),这对于 cp
会导致错误。
但是,如果文件夹中有数千个或更多文件,则应完全放弃通配符方法。 事实是 bash
将通配符扩展为很长的命令行,例如:
cp -a /souce/a /source/b /source/c …… /target
命令行的长度是有限制的,我们可以使用以下命令查出:
getconf ARG_MAX
让我们获取命令行的最大长度(以字节为单位):
2097152
Или:
xargs --show-limits
我们得到类似的东西:
….
Maximum length of command we could actually use: 2089314
….
因此,我们完全不用通配符。
我们就这样写吧
cp -a /source /target
在这里我们面临着行为的模糊性 cp
。 如果 /target 文件夹不存在,那么我们将得到我们需要的内容。
但是,如果目标文件夹存在,则文件将被复制到 /target/source 文件夹。
我们不能总是提前删除 /target 文件夹,因为它可能包含我们需要的文件,而我们的目标是,例如,用 /source 中的文件补充 /target 中的文件。
如果源文件夹和目标文件夹命名相同,例如,我们从 /source 复制到 /home/source,那么我们可以使用以下命令:
cp -a /source /home
复制后,/home/source 中的文件将被 /source 中的文件补充。
这是一个逻辑问题:如果文件夹名称相同,我们可以在目标目录中添加文件,但如果它们不同,则源文件夹将放置在目标目录中。 如何使用 cp 不使用通配符将文件从 /source 复制到 /target?
为了解决这个有害的限制,我们使用了一个非显而易见的解决方案:
cp -a /source/. /target
熟悉DOS和Linux的人都已经明白了:每个文件夹里面有2个不可见的文件夹“.”。 和“..”,它们是指向当前目录和更高目录的伪文件夹链接。
- 复印时
cp
检查是否存在并尝试创建/target/。 - 这样的目录是存在的,它是/target
- /source 中的文件已正确复制到 /target。
所以,把它挂在你记忆中或墙上的一个大胆的框架中:
cp -a /source/. /target
该命令的行为很清楚。 无论您是否拥有一百万个文件或根本没有文件,一切都将毫无错误地运行。
发现
如果您需要复制 所有 文件从一个文件夹到另一个文件夹,我们不使用通配符,最好使用通配符 cp
与源文件夹末尾的句点组合。 这将复制所有文件,包括隐藏文件,并且不会因数百万个文件或根本没有文件而失败。
后记
cp -a -T /source /target
cp -aT /source /target
注意:字母大小写 T
具有意义。 如果你把它混合起来,你会得到完全的垃圾:复制方向会改变。
谢谢:
PS 请通过私人消息发送您发现的任何错误。 我为此增加我的业力。
来源: habr.com