核心原则:减少不必要拷贝、避免误覆盖、善用参数、批量优先用 glob/xargs/rsync、大文件注意缓存
一、常用参数(脚本里最实用)
# -n:不覆盖已存在文件(脚本安全首选,避免误删数据)
cp -n src.txt dest/
# -u:只在源更新(源比目标新 / 目标不存在)才拷贝,增量拷贝
cp -u src.txt dest/
# -a:归档模式,递归、保留权限/属主/时间、软链接不拆(备份目录首选)
# -a = -dR --preserve=all
cp -a src_dir/ dest_dir/
# -R / -r 递归拷贝目录;-R 会保留符号链接,-r 部分老实现会跟随链接
cp -R src_dir dest_dir
# -v 显示过程(调试脚本用,正式脚本建议去掉减少输出)
cp -v src dest
# -f 强制覆盖(慎用!脚本里尽量不要默认加 -f,高危)
⚠️ 重点区分:
cp -a src_dir dest_dir:把src_dir整个放进dest_dir下面cp -a src_dir/ dest_dir:把src_dir/**里面的内容**拷贝到dest_dir(末尾斜杠很关键)
二、批量拷贝:不要写循环 for 逐个 cp(低效)
❌ 不推荐(多次 fork cp 进程,大量文件时很慢)
for f in *.log; do cp "$f" bak/; done
✅ 推荐 glob 一次传给 cp,单进程:
cp -n -- *.log bak/
--作用:防止文件名以-开头被当成命令参数(脚本健壮性必备)
如果文件太多,glob 报 argument list too long(参数过长),改用 xargs:
# 安全写法,带-n,处理空格文件名
find . -maxdepth 1 -type f -name "*.log" -print0 | xargs -0 cp -n -t bak/
-t bak/:指定目标目录,xargs 配合 cp 非常好用。
三、安全写法(脚本必做,防止文件名含空格、换行、特殊字符)
所有变量包裹双引号 "$var"
src="my file.txt"
dest_dir="./target"
cp -n -- "$src" "$dest_dir/"
不加引号遇到
a b.txt直接炸;--拦截-badname.txt
四、增量备份场景:cp -u vs rsync
cp -u 简单轻量,但有短板:只比对 mtime + 大小;不校验内容;不能远程、不支持删除目标多余文件。
简单本地增量、不想依赖 rsync:
cp -au大量文件、需要校验、同步删除、远程:优先
rsync(比循环 cp 高效得多)
rsync -au --delete src_dir/ dest_dir/
五、大文件拷贝优化
连续多次 cp 大文件,Linux page cache 会占内存;脚本里如果需要释放缓存(测试场景):
# 非必要不要随便用,需要root
sync; echo 3 > /proc/sys/vm/drop_caches
如果是重复拷贝同一个大文件,可以考虑
dd、fallocate或者reflink(Btrfs/XFS 支持,零拷贝!)
# btrfs/xfs 同分区下,reflink 几乎瞬间完成,不占用额外空间
cp --reflink=always bigfile.img bigfile-clone.img
注意:跨分区不支持 reflink,会自动回退普通 copy。判断支持性可以捕获返回码。
六、错误处理(脚本里非常重要)
cp 失败返回非 0,配合 set -e 或者手动判断:
#!/bin/bash
set -euo pipefail
if ! cp -n -- "$src" "$dst"; then
echo "拷贝失败:$src" >&2
exit 1
fi
set -e:命令失败直接退出脚本set -u:未定义变量直接报错(防止空变量导致cp / xxx灾难)
七、常见坑清单
不要默认写
cp -rf:无提示覆盖,脚本跑崩数据就没了目录拷贝末尾
/差异,是高频踩坑点文件名以
-开头:必须加--大量小文件:
cp glob>xargs cp> for 循环逐个 cp软链接:
cp -a保留链接;不加-a默认拷贝链接指向的真实文件权限:普通用户无法保留属主,
cp -a在跨用户拷贝时会丢掉 owner
八、模板:一个健壮高效的批量拷贝脚本片段
#!/bin/bash
set -euo pipefail
SRC_DIR="./source"
DST_DIR="./backup"
mkdir -p -- "$DST_DIR"
# 方式1:文件数量不多,glob
cp -au -- "$SRC_DIR"/*.txt "$DST_DIR"/
# 方式2:文件超多,防参数过长,兼容空格文件名
find "$SRC_DIR" -maxdepth 1 -type f -name "*.csv" -print0 |
xargs -0 cp -au -t "$DST_DIR"
九、什么时候不该用 cp?
需要同步、删除目标多余文件 → rsync
跨机器拷贝 → scp /rsync
同文件系统大量快照克隆 → reflink cp(btrfs/xfs)
并行批量拷贝大量文件 → 用 GNU parallel 而不是循环