命令简介

cp命令用来复制文件或者目录,是Linux系统中最常用的命令之一。一般情况下,shell会设置一个别名,在命令行下复制文件时,如果目标文件已经存在,就会询问是否覆盖,不管你是否使用-i参数。但是如果是在shell脚本中执行cp时,没有-i参数时不会询问是否覆盖。这说明命令行和shell脚本的执行方式有些不同。 

命令格式

cp [选项]... [-T] 源 目的

 或:cp [选项]... 源... 目录

或:cp [选项]... -t 目录 源...

命令功能

将源文件复制至目标文件,或将多个源文件复制至目标目录。

命令参数

-a, --archive    等于-dR --preserve=all,--backup[=CONTROL    为每个已存在的目标文件创建备份

-b                类似--backup 但不接受参数--copy-contents        在递归处理是复制特殊文件内容

-d                等于--no-dereference --preserve=links

-f, --force        如果目标文件无法打开则将其移除并重试(当 -n 选项 存在时则不需再选此项)

-i, --interactive        覆盖前询问(使前面的 -n 选项失效)

-H                跟随源文件中的命令行符号链接

-l, --link            链接文件而不复制

-L, --dereference   总是跟随符号链接

-n, --no-clobber   不要覆盖已存在的文件(使前面的 -i 选项失效)

-P, --no-dereference   不跟随源文件中的符号链接

-p                等于--preserve=模式,所有权,时间戳, --preserve[=属性列表   保持指定的属性(默认:模式,所有权,时间戳),如果 可能保持附加属性:环境、链接、xattr 等

-R, -r, --recursive  复制目录及目录内的所有项目

scp命令和执行过程分析

scp是基于ssh的安全拷贝命令(security copy),它是从古老的远程复制命令rcp改变而来,实现的是在host与host之间的拷贝,可以是本地到远程的、本地到本地的,甚至可以远程到远程复制。注意,scp可能会询问密码。
如果scp拷贝的源文件在目标位置上已经存在时(文件同名),scp会替换已存在目标文件中的内容,但保持其inode号。
如果scp拷贝的源文件在目标位置上不存在,则会在目标位置上创建一个空文件,然后将源文件中的内容填充进去。
scp拷贝本质是只是填充内容的过程,它不会去修改目标文件的很多属性。

scp [-12BCpqrv] [-l limit] [-o ssh_option] [-P port] [[user@]host1:]file1 ... [[user@]host2:]file2

选项说明:
-1:使用ssh v1版本,这是默认使用协议版本
-2:使用ssh v2版本
-C:拷贝时先压缩,节省带宽
-l limit:限制拷贝速度,Kbit/s.
-o ssh_option:指定ssh连接时的特殊选项,一般用不上。偶尔在连接过程中等待提示输入密码较慢时,可以设置GSSAPIAuthentication为no
-P port:指定目标主机上ssh端口,大写的字母P,默认是22端口
-p:拷贝时保持源文件的mtime,atime,owner,group,privileges
-r:递归拷贝,用于拷贝目录。注意,scp拷贝遇到链接文件时,会拷贝链接的源文件内容填充到目标文件中(scp的本质就是填充而非拷贝)
-v:输出详细信息,可以用来调试或查看scp的详细过程,分析scp的机制

举例子

1.把本地文件/home/a.tar.tz拷贝到远程服务器192.168.0.7上的/home/tmp,连接时使用远程的root用户:

scp /home/a.tar.tz root@192.168.0.7:/home/tmp/

2.目标主机不写路径时,表示拷贝到对方的家目录下:

scp /home/a.tar.tz root@192.168.0.7

3.把远程文件/home/a.tar.gz拷贝到本机:

scp root@192.168.0.7:/home/a.tar.tz         # 不接本地目录表示拷贝到当前目录 
scp root@192.168.0.7:/home/a.tar.tz /tmp     # 拷贝到本地/tmp目录下

4.拷贝远程机器的/home/目录到本地/tmp目录下。

scp -r root@192.168.0.7:/home/ /tmp

5.从远程主机192.168.10.8拷贝文件到另一台远程主机192.168.10.9上。

scp root@192.168.10.8:/tmp/copy.txt root@192.168.10.9:/tmp

在远程复制到远程的过程中,例如在本地执行scp命令将A主机(192.168.10.8)上的/tmp/copy.txt复制到B主机(192.168.10.9)上的/tmp目录下,如果使用-v选项查看调试信息的话,会发现它的步骤类似是这样的。

# 以下是从结果中提取的过程
# 首先输出本地要执行的命令
Executing: /usr/bin/ssh -v -x -oClearAllForwardings yes -t -l root 192.168.10.8 scp -v /tmp/copy.txt root@192.168.10.9:/tmp
 
# 从本地连接到A主机
debug1: Connecting to 192.168.10.8 [192.168.10.8] port 22.
debug1: Connection established. 
 
# 要求验证本地和A主机之间的连接
debug1: Next authentication method: password
root@192.168.10.8's password:
 
# 将scp命令行修改后发送到A主机上
debug1: Sending command: scp -v /tmp/copy.txt root@192.168.10.9:/tmp
 
# 在A主机上执行scp命令
Executing: program /usr/bin/ssh host 192.168.10.9, user root, command scp -v -t /tmp
 
# 验证A主机和B主机之间的连接
debug1: Next authentication method: password
root@192.168.100.62's password:
 
# 从A主机上拷贝源文件到最终的B主机上
debug1: Sending command: scp -v -t /tmp
Sending file modes: C0770 24 copy.txt
Sink: C0770 24 copy.txt
copy.txt 100% 24 0.0KB/s 
 
# 关闭本地主机和A主机的连接
Connection to 192.168.10.8 closed.

也就是说,远程主机A到远程主机B的复制,实际上是将scp命令行从本地传递到主机A上,由A自己去执行scp命令。也就是说,本地主机不会和主机B有任何交互行为,本地主机就像是一个代理执行者样,只是帮助传送scp命令行以及帮助显示信息。
其实从本地主机和主机A上的~/.ssh/know_hosts文件中可以看出,本地主机只是添加了主机A的信息,并没有添加主机B的信息,而在主机A上则添加了主机B的信息。

Linux命令之---cp/scp