在Linux系统中,复制操作主要依赖两个命令:cp用于本机文件或目录的拷贝,scp用于基于SSH协议在本地与远程主机之间安全传输文件。理解它们的底层机制和参数差异,是日常运维与开发的基本功。很多人在写自动化脚本时误把scp当cp用,导致本地覆盖或权限异常。

一、cp命令:本机复制的基础工具
cp是coreutils软件包提供的标准命令,它通过系统调用open、read、write、close在单个Linux主机的文件系统内完成数据拷贝。无论是ext4、xfs还是tmpfs,只要挂载在同一个内核的目录树中,cp都能操作。其基本语法为cp 源路径 目标路径,当源为目录时必须加-r递归参数。
在实际使用中,权限与属性的保留常常被忽略。默认情况下cp会创建新文件,属主为执行用户,时间戳更新为当前时间。若需要备份系统配置,应当使用-a选项(等价于-dR --preserve=all),它会保留符号链接、文件权限、属主及SELinux上下文。下面是一段典型的本地备份代码:
# 将/etc目录下所有内容归档式复制到/backup/etc # -a 保留所有属性,-v 显示过程 cp -av /etc /backup/etc # 若只复制单个文件并强制覆盖不提示 cp -f /home/user/app.conf /opt/app/app.conf
cp还有一些实用但少用的参数。--backup=numbered可在覆盖前生成带编号的备份文件,避免误删;-u仅当源文件比目标新时才复制,适合增量同步。需要注意的是,cp不支持断点续传,大文件复制中断只能重头再来,这也是它和专用同步工具rsync的区别之一。
二、scp命令:跨主机的加密复制
scp全称secure copy,它并非独立文件传输协议,而是包装了ssh客户端,在远程登录的通道里执行读写。因此只要机器开了sshd服务且网络互通,就能用scp互传。它的路径写法区分本地与远程:远程格式为用户@主机:路径。例如从本地推送到服务器,或拉取远程日志到本地。
由于走SSH,scp天然具备加密与身份认证能力,比ftp或telnet安全得多。但它也有明显短板:不支持断点续传、不支持排除文件列表、传输前需完成整体加密握手。在复制大量小文件时,因频繁建连效率偏低。以下示例展示常见用法:
# 本地文件传到远程主机的/tmp下 scp -P 2222 ./report.zip user@192.168.0.1:/tmp/ # 从远程拉取整个目录到本地当前目录 scp -r -P 2222 user@192.168.0.1:/var/log/nginx ./nginx_logs # 使用密钥免密传输 scp -i ~/.ssh/id_rsa ./data.sql user@127.0.0.1:/home/user/
使用scp时要特别注意端口参数是大写-P,而ssh命令是小写-p,写错会导致连接失败。另外,若远程路径含空格或特殊字符,需用英文单引号包裹。由于scp在较新OpenSSH版本中已标记为不推荐,新项目可逐步迁移到rsync over ssh,但存量脚本仍广泛依赖它。
三、cp与scp的选型对比
二者核心区别在于作用域:cp只认本机挂载点,scp解决机器间搬运。如果只是在同一块磁盘或同一系统里挪数据,用cp更快且不需联网认证;一旦涉及跨服务器发布代码、取回日志,就必须用scp或等价工具。从权限角度看,cp的-a能完整镜像属主,而scp默认在远端以登录用户创建文件,需用-p尝试保留时间但未必保属主。
我们通过一个简表归纳关键差异:
| 维度 | cp | scp |
|---|---|---|
| 作用范围 | 单主机内 | 本地与远程间 |
| 传输加密 | 否 | 是(SSH) |
| 递归目录 | 需-r | 需-r |
| 断点续传 | 不支持 | 不支持 |
| 典型场景 | 本地备份、整理 | 发布、取数 |
在编写运维脚本时,可先判断变量里是否出现@与:来识别远程路径,从而自动切换命令。例如用shell函数封装,本地走cp,远程走scp,既统一调用接口,又避免人为选错。对于超大数据集,建议放弃scp改用rsync -avz -e ssh,以获得增量与续传能力。
四、常见错误与正确写法
新手常犯的错误之一,是在scp中漏写远程用户名,写成scp file 192.168.0.1:/tmp,此时默认用当前本地用户去连,若远端无同名账号便拒绝。其二是用cp去复制挂载在sshfs以外的网络盘却以为跨机,实际仍属本机挂载点,权限混乱。下面给出一段防错封装示例:
# 安全复制函数:自动识别远程路径
safe_copy() {
src="$1"
dst="$2"
# 目标含@和:视为远程
case "$dst" in
*@*:*)
scp -r -P 2222 "$src" "$dst" ;;
*)
cp -a "$src" "$dst" ;;
esac
}
# 调用示例
safe_copy ./conf user@127.0.0.1:/opt/conf
safe_copy ./conf /opt/conf
另一个隐患是覆盖不发生提示。cp默认若目标存在且为非写保护普通文件会静默覆盖,脚本里应加-i交互或先test -e判断。scp同样会直接覆盖远端文件,且无回收站概念。重要操作前用--backup或先 rsync 到临时目录再移动,能大幅降低事故率。掌握这些细节后,linux下的复制任务就能稳当高效完成。