cp
SYNOPSIS
cp [OPTION]... [-T] SOURCE DEST
cp [OPTION]... SOURCE... DIRECTORY
cp [OPTION]... -t DIRECTORY SOURCE...
其实 cp 的选项比我想象中的要多很多。
其他选项:
- 创建硬链接(
-l
)而不是拷贝。 -L
则会先解引用符号链接。-n
不会覆盖旧文件。-a
先归档再拷贝,也就是保留所有属性。-r
递归拷贝(文件夹)。-u
只拷贝时间上更新的文件。
在 shell 中合并两个目录可以用 rsync:
rsync -auvh A/ B
au 选项 cp 也有,h 表示用人类可读单位显示体积,v 表示 verbose。注意:
- 如果 A 后面没有斜杠,无论 B 是否存在,都会将 A 作为子文件夹拷贝进去。
- 如果用
A/*
,则匹配不到隐藏文件。 - B 后面有没有斜杠应该是不影响。
- rsync 用于文件夹合并时,
-r
选项是必须要加的,也就是至少需要rsync -r A/ B
。加-a
也能满足这一点,因为-a
/--archive
和-rlptgoD
是等价的。(-r
表示递归,-l
表示以符号链接形式拷贝符号链接,-p
表示保留权限,-t
表示保留时间,-g
表示保留 group,-o
表示保留 owner,-D
等价于--devices --specials
,即保留块设备和特殊设备(FIFO、socket 等)。)
如何用 cp 来模拟这种行为?
首先假设源文件 A 存在,B 可能不存在。B 如果存在且为普通文件则报错。
方案 1:使用 cp -r A B
❌ 不加 *
时,若目标文件夹存在,源文件夹本身被复制成为子文件夹。
$ rm -rf A B
$ mkdir -p A/1/2/3 B
$ cp -r A B
$ tree B
B
└── A
└── 1
└── 2
└── 3
5 directories, 0 files
✔️ 若目标文件夹不存在,相当于使用 cp -r A B
$ rm -rf A B
$ mkdir -p A/1/2/3
$ cp -r A B
$ tree B
B
└── 1
└── 2
└── 3
4 directories, 0 files
方案 2:使用 cp -r A/* B
缺点:*
不能匹配上 Linux 的隐藏文件!
✔️ 若目标文件夹存在,工作正常。
$ rm -rf A B
$ mkdir -p A/1/2/3 B
$ cp -r A/* B
$ tree B
B
└── 1
└── 2
└── 3
4 directories, 0 files
❌ 若目标文件夹不存在,而源文件夹的子文件夹又恰好只有一个,则把子文件夹当成源文件夹拷贝。
$ rm -rf A B
$ mkdir -p A/1/2/3
$ cp -r A/* B
$ tree B
B
└── 2
└── 3
3 directories, 0 files
❌ 如果目标文件夹不存在,且源文件夹的子文件夹有多个,则会失败:
$ rm -rf A B
$ mkdir -p A/1/2/3
$ mkdir -p A/4/2/3
$ cp -r A/* B
cp: target 'B': No such file or directory
加了 -t
选项之后会加上文件夹存在性检查,并在两种情况下都直接报错。
思考:所谓合并,就是目标文件夹可能存在,也可能不存在。存在时拷贝子文件夹,不存在时拷贝整个文件夹。
比较稳妥的模拟 rsync 效果的方法是?
find 的 + 模式并不会对每个输出都发起命令,而是将所有输出汇总后才发出。同时如果没有输出则会忽略这个命令,因而可以用来达到和 rsync 类似的效果。
mkdir -p B
find A -mindepth 1 -maxdepth 1 -exec cp -r -t B {} +
用 find 而不是 cp 的好处是也能找到隐藏文件。