看别人的部署脚本,经常见到 cp -v、cp -rv、cp -av 这些写法。v 就一个字母,很多新手直接跳过不看,结果是复制出了问题也发现不了,全被静默吞掉了。

-v 就是 verbose

verbose 意思是「啰嗦」,加上之后 cp 会把每一个被复制的文件名打印出来:

cp -v a.txt b.txt
'a.txt' -> 'b.txt'

不加的时候,cp 成功就一声不吭。Linux 的哲学是「没有消息就是好消息」,但脚本里恰恰需要这份消息:出了问题能对照日志找出是哪个文件没复制过去。

常和哪些参数一起用

  • -r 或 -R:递归复制目录,复制文件夹必须加,否则报「omitting directory」。
  • -a:归档模式,等于 -dR --preserve=all,保留权限、所有者、时间戳、软链接。备份、部署最常见的就是 cp -av。
  • -i:覆盖前询问,交互场景用。
  • -n:不覆盖已存在的文件。
  • -u:只复制更新的文件,增量备份用。

最常用的一条:

cp -av /var/www/app/ /backup/app_$(date +%F)/

注意末尾的斜杠

这是个老坑。cp -a src dst,如果 dst 不存在,结果是 dst 变成 src 的副本;如果 dst 存在,结果是 dst/src。加不加斜杠、目标存不存在,结果不一样。写脚本前先在临时目录试一下,别在线上凭感觉敲。

-v 带来的副作用

复制几万个文件时,-v 会疯狂刷屏,SSH 连接都能被拖慢。这时候把输出重定向到日志:

cp -av src/ dst/ >> /var/log/backup.log 2>&1

想看进度又不想要几十万行日志,可以用 rsync 替代,它的 --progress 和 --info 更友好,还支持增量同步和断点续传。cp 只适合小规模的一次性复制。

一个容易忽略的细节

cp 默认不保留时间戳,用 -a 才会保留。做打包和构建缓存时,时间戳不一致会导致增量编译判断出错,所以构建脚本里也应该养成加 -a 的习惯。