
本文将揭示一些与复制时使用
通配符 ,复制时
cp
命令的模棱两可的行为以及正确复制大量文件而不会遗漏和崩溃的方法有关的一些非显而易见的内容。
假设我们需要将所有内容从/源文件夹复制到/目标文件夹。
首先想到的是:
cp /source/* /target
立即将此命令修复为:
cp -a /source/* /target
-a
开关将添加所有属性,权限的副本并添加递归。 如果不需要精确复制权限,则
-r
开关就足够了。
复制后,我们发现并非所有文件都被复制了-从像这样的点开始的文件被忽略:
.profile
.local
.mc
等等。
为什么会这样呢?
因为通配符处理shell(在典型情况下为
bash
)。 默认情况下,bash将忽略所有以句点开头的文件,因为它将其视为隐藏文件。 为了避免这种行为,我们必须使用以下命令更改
bash
的行为:
shopt -s dotglob
要在重新引导后保存此行为更改,可以使用此命令在
/etc/profile.d
文件夹中创建wildcard.sh文件(您的发行版可能具有其他文件夹)。
而且,如果源目录中没有文件,则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将文件从/源复制到/目标?
为了解决这一有害限制,我们使用了非显而易见的解决方案:
cp -a /source/. /target
那些熟悉DOS和Linux的人已经了解了一切:每个文件夹中都有2个不可见的文件夹“”。 和“ ..”,它们是指向当前目录和更高目录的伪文件夹链接。
- 复制时,
cp
检查是否存在并尝试创建/ target /。 - 这样的目录存在,它是/ target
- 来自/源的文件已正确复制到/目标。
因此,我们在记忆中或墙上悬挂着一个大胆的框架:
cp -a /source/. /target
该命令的行为是明确的。 不管您有百万个文件还是根本没有文件,一切都会正常运行。
结论
如果要将
所有文件从一个文件夹复制到另一个文件夹,则不要使用通配符,而最好使用
cp
和源文件夹末尾的点来代替通配符。 这将复制所有文件,包括隐藏的文件,并且不会因数百万个文件或完全没有文件而失败。
后记
vmspike建议使用类似的命令变体:
cp -a -T /source /target
Oz_Alex cp -aT /source /target
注意:字母
T
的大小写很重要。 如果将它们混合在一起,则会得到完整的垃圾:复制的方向将会改变。
致谢:
您在PM中注意到的
PS Direct错误。 我为此增加业力。
