Linux命令之---cp/scp
命令简介
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的信息。