cp 命令详解
更新时间:2026-08-29。本文是「一个命令一个文档」系列,属于文件与目录操作命令族。复制是最频繁的文件操作之一,
cp用得好能省掉无数手动操作。
为什么写 cp?因为它有个最危险的默认行为:同名直接覆盖,不提示。很多人第一次 cp a.conf b.conf 把配置覆盖后才发现没备份。理解 -i/-b/-n 这几个开关,能救你于水火。
cp(copy,复制)把一个或多个源复制到目标。源可以是文件或目录,目标可以是不存在的路径(自动创建父目录不行,需 -r 配合)。
一、最基本的用法
cp a.txt b.txt # 文件复制,b.txt 不存在则新建,存在则覆盖
cp a.txt b.txt c.txt dir/ # 多个源 + 最后一个必须是目录,全部拷进去
cp file /backup/ # 拷到目录,文件名保持 file关键陷阱:目标若已存在同名文件,
cp默认静默覆盖——没有确认、没有回收站。生产环境第一反应应该是习惯性加-i或-b。
二、高频选项一张表(覆盖九成场景)
| 选项 | 作用 | 示例 |
|---|---|---|
-r / -R | 递归复制目录(必加,否则目录复制报 omitted) | cp -r src/ dst/ |
-i | 覆盖前交互确认 | cp -i a b |
-n | 不覆盖已存在的目标(no-clobber) | cp -n a b |
-u | 仅当源更新时才复制(update) | cp -u src/* dst/ |
-b | 覆盖前先备份目标(加 ~ 后缀) | cp -b a.conf b.conf |
-p | 保留模式、属主、时间戳 | cp -p a b(备份常用) |
-a | 归档模式 = -drp(递归+保留全部属性+符号链接不展开) | cp -a src/ dst/ |
-v | 显示正在复制什么(verbose) | cp -rv src/ dst/ |
-l | 创建硬链接而非复制数据 | cp -l a b |
-s | 创建符号链接而非复制 | cp -s a b |
--preserve | 精细控制保留哪些属性 | cp --preserve=mode,ownership |
-a(archive)是做目录镜像/备份的黄金选项:递归、保留权限属主时间戳、符号链接保持为链接(不跟进去复制)。比手动拼-r -p更可靠。
三、实战 demo
demo 1:安全复制,覆盖前先备份(防误删配置)
cp -b nginx.conf nginx.conf.bak # 若 nginx.conf.bak 已存在会被改名成 .bak~ 再复制
# 或者更直观:
cp -i nginx.conf nginx.conf.bak # 存在则问 y/n做改动前先 cp -b 留一手,比事后找恢复省心。
demo 2:递归复制整个项目目录
cp -r myapp/ myapp.bak/
# 目录复制必须 -r,否则报错 "omitting directory"
# 完整备份用 cp -a 保留所有属性:
cp -a myapp/ myapp.bak/demo 3:只同步新增/变更的文件(增量更新)
cp -u src/* deploy/ # 只有 src 里比 deploy 新的文件才复制
# 适合"本地改了几个文件,推到部署目录"的场景,避免全量重拷demo 4:用硬链接省空间(大文件多份但不占双倍)
cp -l bigfile.iso bigfile-link.iso
# 两个文件名指向同一份数据块,改一个另一个也变(硬链接特性)
# 只是想"引用"而不复制数据时用;纯快捷方式用 -s 软链接demo 5:复制时显示进度,心里有底
cp -v hugefile.iso /mnt/backup/
# 大文件复制没进度条会焦虑,-v 至少告诉你正在拷哪个
# 想要真正进度条,可用 rsync --progress,见 rsync四、硬链接 vs 符号链接
-l 和 -s 都"不真正复制数据",但本质不同:
- 硬链接(
-l):新名字和原文件指向同一个 inode(数据块)。删除任一,数据还在(直到最后一个链接消失)。不能跨文件系统,不能链接目录。 - 符号链接(
-s):新文件是个"快捷方式",存的是指向原路径的字符串。原文件删除,软链就悬空(断链)。可跨文件系统、可链目录。
cp -s /opt/app/bin/app ~/bin/app # 常用:把程序软链到 ~/bin,升级只换源
ls -l ~/bin/app # 显示 -> /opt/app/bin/app改 ln 是专门创建链接的命令,比 cp -l/-s 更常用。
五、和 mv / rsync 的分工
- mv(move,移动/重命名):同文件系统下只是改目录项,不复制数据,极快;跨文件系统才真正拷贝+删除。单纯改名用 mv,见 mv。
- rsync:增量同步、可断点、可远程、有进度条,目录同步/备份首选。大目录或远程复制别用
cp -r,用 rsync。
# 本地目录镜像(删目标多余文件,保持完全一致)
rsync -a --delete src/ dst/六、常见坑
- 复制目录忘加
-r→cp: omitting directory。谨记目录必须递归。 cp a b c dir/中前 N-1 是源、最后一个是目标目录;若最后一个不是目录会报错。-p保留属主通常需要 root,普通用户复制会丢属主(变自己)。备份系统文件记得 sudo。- 通配符
cp *.log /tmp在文件极多时报"参数过长",改用find . -name '*.log' -exec cp {} /tmp \;。
七、进阶:备份与同步的真实套路
cp 在运维里最常见的两个角色——"留一手备份"和"增量同步"——都有更稳的写法:
# 改动配置前先留带时间戳的备份,绝不覆盖原文件
cp -a nginx.conf "nginx.conf.bak-$(date +%Y%m%d-%H%M%S)"
# 同步一个目录到另一处,只复制更新的(-u),并保留全部属性(-a)
cp -au src/ deploy/
# 大量小文件复制,加 -v 配合 | pv 能看到进度(需装 pv)
cp -a bigdir/ /backup/bigdir/-a(archive)= -dR --preserve=all,是做目录镜像的黄金选项:递归、保留权限/属主/时间戳、符号链接保持为链接不跟进去。比手敲 -r -p 更可靠,也避免了"软链被展开成实体文件、目录瞬间膨胀"的坑。
八、边界与坑的延伸
- 覆盖没有回收站:
cp a b若b已存在,原b直接被覆盖且不可恢复。生产脚本里习惯性alias cp='cp -i'写进.bashrc,或凡改重要文件先-b留备份。 - 属性保留需要权限:
-p/-a保留属主通常要 root,普通用户复制系统文件会丢属主(变成自己),还原时记得sudo cp -a。 - 跨文件系统复制是"真拷贝":同盘内
cp也是复制数据(不像 mv 只改目录项),大目录该用 rsync 做增量,第二次跑只补差异,快得多。 cp -l硬链接的副作用:两个名字指向同一份数据,改其中一个另一个也变。想"引用但不共享数据"用-s软链接;纯备份别用-l,否则误改源文件把备份一起改了。- 通配符爆炸:
cp *.log /tmp在文件极多时报"参数过长",改用find . -maxdepth 1 -name '*.log' -exec cp {} /tmp \;。
选型逻辑:本地一次性镜像用
cp -a;要增量、要断点、要远程,换 rsync。别拿cp -r去干 rsync 的活,大目录会哭。
相关命令
一句话总结
cp = 复制文件/目录:目录必须 -r(归档用 -a 保留全部属性),默认同名静默覆盖——用 -i 确认、-b 先备份、-n 不覆盖、-u 只更新来防丢数据;-l 硬链接/-s 软链接不真复制数据;大目录或远程同步换 rsync 更稳。