使用单个命令复制多个文件的方法:SCP或SFTP?

487

我想从/向不同目录的远程服务器复制文件。 例如,我希望同时运行这4个命令。

scp remote:A/1.txt local:A/1.txt
scp remote:A/2.txt local:A/2.txt
scp remote:B/1.txt local:B/1.txt
scp remote:C/1.txt local:C/1.txt

最简单的方法是什么?


22
制作脚本时,我不得不为每个命令设置密码。我能避免这个吗? - user987654
15
不要以这种方式重复使用密码:scp remote:“A/1.txt A/2.txt B/1.txt C/1.txt” local:./ - JohnMudd
https://dev59.com/k2oy5IYBdhLWcg3wFqFT#23748561(被提名为此问题的重复)有一个很好的额外技巧。 - tripleee
3
我建议你查看rsync,它可能有助于你处理当前和许多未来的情况。为了避免输入密码(更不用说多次了),你应该了解ssh公钥/私钥,例如 https://www.digitalocean.com/community/tutorials/how-to-set-up-ssh-keys--2 - mnagel
2
基于@JohnMudd的答案,示例为:scp root@192.168.56.120:'/etc/openvpn/ca.crt /etc/openvpn/client/client0.crt /etc/openvpn/client/client0.key /etc/openvpn/client/ta.key' ./ - Eduardo Lucio
19个回答

615

将多个文件从远程复制到本地:

$ scp your_username@remote.edu:/some/remote/directory/\{a,b,c\} ./

将多个文件从本地复制到远程:

$ scp foo.txt bar.txt your_username@remotehost.edu:~
$ scp {foo,bar}.txt your_username@remotehost.edu:~
$ scp *.txt your_username@remotehost.edu:~

从远程复制多个文件到远程:

$ scp your_username@remote1.edu:/some/remote/directory/foobar.txt \
your_username@remote2.edu:/some/remote/directory/

来源:http://www.hypexr.org/linux_scp_help.php


5
第一个指令缺少结尾的“。”,而'{a,b,c}'等同于{a,b,c}。 - duleshi
14
我认为OP试图将多个本地文件夹中的多个文件复制到多个远程文件夹中,这些示例无法完成任务,因为它们只会将文件scp到~./ - aesede
38
注意:花括号内逗号后不要加空格。我刚刚浪费了10分钟来弄清楚为什么我的命令无法运行,原因就是有空格存在。 - deepak
21
从远程复制到本地时,{a,b,c}并不完全等同于\ {a,b,c },因为前者需要每个文件都输入密码,而后者只需要输入一次密码。 - Marcelo Ventura
24
@MarceloVentura,@duleshi:另外,我想补充的是,使用\{a,b,c\}将在单个连接/批次中传输文件(因为它们将在远程主机上展开),而使用{a,b,c}将打开多个连接,并且在传输许多文件时开销非常明显。 - omninonsense
显示剩余11条评论

327

从本地上传到服务器:

scp file1.txt file2.sh username@ip.of.server.copyto:~/pathtoupload

从服务器下载到本地(OpenSSH v9.0之前):

scp -T username@ip.of.server.copyfrom:"file1.txt file2.txt" "~/yourpathtocopy"

从服务器下载到本地(OpenSSH v9.0+):

scp -OT username@ip.of.server.copyfrom:"file1.txt file2.txt" "~/yourpathtocopy"

参考man 1 scp

-O      Use the legacy SCP protocol for file transfers instead of the SFTP protocol.  Forcing the use of the
        SCP protocol may be necessary for servers that do not implement SFTP, for backwards-compatibility for
        particular filename wildcard patterns and for expanding paths with a ‘~’ prefix for older SFTP
        servers.

HISTORY
        Since OpenSSH 9.0, scp has used the SFTP protocol for transfers by default.

20
因为服务器不会要求每个文件的密码,所以这应该是最佳答案 :) - motagirl2
4
只要使用反斜杠转义花括号,顶部答案不需要为每个文件输入密码。但是这个答案却显示找不到文件错误。请注意不要改变原意。 - Pluto
1
“server to local” 不起作用。它为什么有87个赞,我不知道。 - Deanie
2
第二个在我的机器上可以运行,但只有没有-T选项。 - Richard DiSalvo
1
在Windows上通过Get-Command scp获取的版本7.7.2.1中似乎没有-T选项。不过即使不加-T,该命令也可以正常工作。 - dtasev
显示剩余3条评论

99
你可以使用-r开关复制整个目录,因此如果你可以将文件隔离到自己的目录中,就可以一次性复制所有内容。
scp -r ./dir-with-files user@remote-server:upload-path

scp -r user@remote-server:path-to-dir-with-files download-path

例如,

scp -r root@192.168.1.100:/var/log ~/backup-logs

或者如果它们只有几个,您可以使用:

scp 1.txt 2.txt 3.log user@remote-server:upload-path

如果我的目标是根目录,而我正在复制/etc目录,比如:scp -r /backups/etc root@linuxbox:/,那么这个命令会生效吗?我的源目录只包含一些像“hosts”和nginx/sites-available等稀疏文件。 - Tomachi

80

正如Jiri所提到的,你可以使用scp -r user@host:/some/remote/path /some/local/path来递归地复制文件。这假定存在一个包含所有要传输文件(且没有其他内容)的单个目录。

然而,如果你想从多个不同的目录传输文件,并且目标不相同,则SFTP提供了一种替代方法:

sftp user@host << EOF
  get /some/remote/path1/file1 /some/local/path1/file1
  get /some/remote/path2/file2 /some/local/path2/file2
  get /some/remote/path3/file3 /some/local/path3/file3
EOF

这个例子使用“here doc”语法来定义一系列SFTP输入命令。作为另一种选择,您可以将SFTP命令放入文本文件中并执行sftp user@host -b batchFile.txt


11
这是唯一真正回答了问题的答案。谢谢。我已经花费太长时间在谷歌和分析“scp”手册上,试图找到这个功能,但我猜测“scp”没有它。 - sudo
3
这似乎是最好、最灵活的答案。注意:在我意识到需要使用完整路径(如/home/vagrant/Code/而不是~/Code/)之前,我遇到了一些麻烦。 - Ryan
这是最好的答案,只是不要忘记为目录添加“-r”。 - Chris_Rands
只有在您设置了公钥身份验证时,此功能才能正常工作。 - Sahil Chimnani

42

使用{file1,file2,file3}的答案仅适用于bash(远程或本地)

真正的方法是:

scp user@remote:'/path1/file1 /path2/file2 /path3/file3' /localPath

1
太棒了!有时我使用非bash shell,这对我帮助很大。不仅是正确的方法,而且是正确的方式。 - Paul B.
1
使用 {…, …, …} 进行文件名扩展在许多 shell 中都可以工作,而不仅仅是 Bash。然而,这种方法在任何 shell 中都可以工作,因此显然更好。 - Piotr Dobrogost
2
需要更多的引用。这些路径可能包含空格。 - Amit Naidu
1
太好了!我想给它点赞很多次,但我只能点一次!谢谢Vouze! - André Pacheco
1
你的 '/path1/file1 /path2/file2 /path3/file3' 由于空格而产生了“协议错误:文件名与请求不匹配”的问题。请使用 -T 选项。 - Alex Barker
我弄不明白为什么它对我不起作用。 - undefined

27

玩了一段时间的scp后,我发现最稳健的解决方案:

(小心单引号和双引号)

本地到远程:

scp -r "FILE1" "FILE2" HOST:'"DIR"'

远程到本地:

scp -r HOST:'"FILE1" "FILE2"' "DIR"

请注意,“HOST:”后面的任何内容都将被发送到远程并在那里解析。因此,我们必须确保它们不会被本地shell处理。这就是单引号的作用。双引号用于处理文件名中的空格。

如果文件都在同一个目录中,我们可以使用*来匹配所有文件,例如:

scp -r "DIR_IN"/*.txt HOST:'"DIR"'
scp -r HOST:'"DIR_IN"/*.txt' "DIR"

与仅受一些shell支持的“{}”语法相比,这个是通用的。


感谢您帮忙处理文件名中的空格。我使用了{}方法,所以在引用后也必须使用\进行转义。 - Noumenon
3
如果你想在路径中使用波浪号字符(~)代表你的主目录,请注意波浪号和斜杠必须在引号外面。 scp -r robwaa@192.168.1.101:'~/"bin/set-vpn-kill-switch" ~/"bin/flush-iptables"' ~/"" - Rob Waa
“{}”语法使得从同一目录中复制多个文件更加容易。是否有办法在使用“scp -r”时,将“FILE1”“FILE2”作为相对路径而不是文件的绝对路径? - dtasev

16

问题: 使用单个SCP命令将多个目录从远程服务器复制到本地计算机,并保留每个目录在远程服务器中的状态。

解决方案: SCP可以轻松实现此操作。这解决了使用SCP与多个文件夹时需要多次输入密码的烦恼。因此,这也节省了大量时间!

例如:

# copies folders t1, t2, t3 from `test` to your local working directory
# note that there shouldn't be any space in between the folder names;
# we also escape the braces.
# please note the dot at the end of the SCP command

~$ cd ~/working/directory
~$ scp -r username@contact.server.de:/work/datasets/images/test/\{t1,t2,t3\}  .

PS:受到这个很好的答案的启发:scp或sftp使用单个命令复制多个文件


根据评论,在Windows上的Git Bash也可以正常工作


7
好的,我会尽力以最准确和易懂的方式翻译以下内容:P.S. 不要在项目之间添加空格。即 {t1,t2,t3} ------> 我在这里浪费了十分钟... 哈哈 - kenberkeley
1
这是最佳答案,因为当您转义大括号时,它将被解释为单个命令,并且不会要求每次传输输入密码。 - Amaynut
@Amaynut 是的,没错!那肯定可以节省很多时间和精力 :) - kmario23

16

最简单的方法是

local$ scp remote:{A/1,A/2,B/3,C/4}.txt ./

所以{..}列表可以包括目录(这里的A、B和C是目录;"1.txt"和"2.txt"是这些目录中的文件名)。

虽然它会将这四个文件都复制到一个本地目录中——不确定这是否符合您的要求。

在上述情况下,您最终将远程文件A/1.txt、A/2.txt、B/3.txt和C/4.txt复制到单个本地目录中,并使用文件名./1.txt、./2.txt、./3.txt和./4.txt。


1
这样做会不会覆盖本地机器上 A/1.txt 的内容,用 B/1.txt 的内容替换它? - Yves Dorfsman
好的,调整了示例(现在不会覆盖),并添加了描述。谢谢。 - Tagar
花括号扩展是 Bash 的一个特性,不适用于例如 POSIX sh - tripleee
1
@tripleee,谢谢。它可能不是POSIX,但它不仅在bash中工作。我一直在使用ksh,它也可以在那里工作。 - Tagar
1
你也可以通过以下方式混合目录和文件进行复制:local$ scp -r remote:{A/1.txt,A/2.txt,B/3.txt,C/4.txt,D,F} ./ - donhector

12

您可以这样做:

scp hostname@serverNameOrServerIp:/path/to/files/\\{file1,file2,file3\\}.fileExtension ./

这将会下载所有列出的文件名到你所在的本地目录。

请确保不要在每个文件名之间放置空格,只需使用逗号,隔开。


4
如果扩展名相同,这样做很好。如果文件的扩展名不同,可以将其写成/path/to/files/\{file1.ext,file2.ext,file3.ext\}。注意,对于PowerShell人员(现在微软已经加入了这一行列),您需要使用\``进行转义:/path/to/files/`{file1.ext,file2.ext,file3.ext`}`。 - dtasev
如何使用scp命令传输多个相同扩展名的文件?我尝试过"{file1,file2}".pdf{"file1,file2"}.pdf,但都无法正常工作:提示“没有这样的文件或目录”。然而,对于单个文件,您提供的第一个选项可以正常工作。但是,对于多个文件,应该怎么做呢?请帮忙解决! - Pathros

11

复制多个目录:

scp -r dir1 dir2 dir3 admin@127.0.0.1:~/

问题是如何从远程目录复制到本地目录,而不是相反。 - Tagar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接