cp -r 是 Linux 中递归复制目录的标准命令,-r 参数启用递归模式以复制子目录、隐藏文件及符号链接;目标不存在时新建同名目录,存在且为目录时嵌套存放,存在且为文件则报错;默认不保留权限等元数据,需加 -p 或 -a 选项。

cp -r 是最常用也最容易出错的命令,关键不在“能不能复制”,而在于“复制成什么结构”——目标目录是否存在、要不要保留源目录名、隐含文件要不要包含,全由写法决定。
用 cp -r src/ dest/ 时,dest 必须是已存在的目录
如果 dest/ 不存在,这条命令会把整个 src/ 目录(连名字一起)复制过去,结果是 dest/src/。这不是你想要的“把 src 里的内容放进 dest”。
常见错误现象:cp: target 'dest' is not a directory,说明 dest 根本没建好。
- 先确认目标目录存在:mkdir -p dest
- 再执行:cp -r src/. dest/(注意末尾的 .)
- 不要用 src/*:它会漏掉所有以 . 开头的隐藏文件(如 .git、.env)
cp -r src/. dest/ 和 cp -r src/* dest/ 的区别很实在
前者复制 src 下所有内容(含隐藏项),直接铺平到 dest/;后者只复制非隐藏的一级条目,且遇到子目录内有空格或特殊字符时可能报错(shell 展开失败)。
- 如果你刚跑完 git clone 想把代码“内容”搬进已有站点目录,就用 src/.
- 如果你明确只要 .js 和 .html 文件,不用隐藏配置,才考虑 src/*.js src/*.html 这种显式列举
- cp -a 可替代 -r,还能保留权限、时间戳、符号链接属性,生产环境建议优先用它
目标目录不为空时,覆盖行为要主动控制
默认 cp 遇到同名文件会静默覆盖(除非系统 alias 了 -i),但某些发行版或 shell 配置会让它卡在交互提示上,导致脚本中断。
- 加 -f 强制覆盖:cp -af src/. dest/
- 但别盲目加 -f:如果 dest/ 里有你手动改过的配置文件,会被无声替换
- 更稳妥的做法是先清理再复制:rm -rf dest/* dest/.* 2>/dev/null; cp -a src/. dest/(注意 .* 会匹配到 dest/. 和 dest/..,所以加 2>/dev/null 抑制报错)
真正容易被忽略的是「路径结尾斜杠」和「点号位置」——src/. 中的 . 不是可有可无的装饰,它是让 shell 把当前目录下所有条目(包括隐藏项)作为独立参数传给 cp 的关键。少一个点,就可能丢掉整个 .git 目录。


















