如何在Linux中通过scp复制文件时转义路径中的空格?

440

我想将一个文件从远程系统复制到本地系统。现在我正在使用Linux系统中的scp命令。我的一些文件夹或文件名中包含空格,当我尝试复制这些文件时,它会显示错误信息:“没有这样的文件或目录”。

我尝试过:

scp ael5105@192.168.0.200:'/home/5105/test/gg/Untitled Folder/a/qy.jpg' /var/www/try/

我在网上看到了一些参考资料,但我并不完全理解,请问有人可以帮忙吗?

在复制时如何转义文件名或目录名中的空格...


请仔细检查文件是否真实存在。将引号放在整个路径周围,包括登录名和IP地址。或者,删除引号并在空格前加上反斜杠。 - user707650
13个回答

686

基本上你需要对它进行两次转义,因为它在本地进行了转义,然后在远程端也进行了转义。

你有几个选择(在bash中)可以做:

scp user@example.com:"web/tmp/Master\ File\ 18\ 10\ 13.xls" .
scp user@example.com:web/tmp/Master\\\ File\\\ 18\\\ 10\\\ 13.xls .

另一个选项仅适用于旧版本的OpenSSH和可能的其他客户端:
scp user@example.com:"'web/tmp/Master File 18 0 13.xls'" .

18
在Mac上和大多数控制台应用程序(如Terminal)中,有一个“粘贴转义文本”的选项。因此我使用了第二个选项。 - Sacrilicious
15
“path”可以正常使用,而‘path’出现错误;结论是应该先使用单引号再使用双引号来包裹。 - user4104817
8
哇!这可能是我见过的最荒谬的程序行为! - jankes
13
@jankes 它并非没有优点。你在那里放置的是一个 shell 命令参数,这使得你可以执行一些操作,比如 scp user@example.com:'$(ls -t | head -1)' . 以获取服务器上最近创建的文件,或者 scp user@example.com:'dir/*.{xml,pdf}' . 以从远程目录获取所有的 xml 和 pdf 文件。总的来说,我更喜欢这种方法而不是为具有空格的文件提供方便。带有空格的文件总是很麻烦。 - JoL
3
如何知道在另一端将要使用哪个shell,以便知道应用哪种引号语法进行内部引用?这种方法是否只能在脚本中使用,而且脚本作者可以控制另一端的shell? - codeshot
显示剩余7条评论

104

作品

scp localhost:"f/a\ b\ c" .

scp localhost:'f/a\ b\ c' .

无法工作

scp localhost:'f/a b c' .

这是因为在路径传递到scp命令之前,字符串会被shell解释。因此,当它传递到远程主机时,远程主机将寻找一个具有未转义引号的字符串,从而导致失败。

要验证这一点,请使用-vx选项启动shell,即bash -vx,它将显示运行命令的插值版本。


1
使用单引号并进行转义对我有效,但双引号无效。 - Mauricio Trajano
1
@MauricioTrajano 看一下 https://www.gnu.org/software/bash/manual/html_node/Quoting.html 所有的引号都有不同的作用。在上面的简单情况中,双引号 " 或单引号 ' 的效果相同。 - Vorsprung

60

在目录名称中使用三个反斜杠来转义空格:

scp user@host:/path/to/directory\\\ with\\\ spaces/file ~/Downloads

将复制远程目录中名为directory with spacesfile到您的Downloads目录。


2
这是唯一在Ubuntu 19.10上为我工作的方法。没有双引号,没有软引号和硬引号,也没有转义引号。只有三个反斜杠空格。非常奇怪。谢谢! - uldics
爆炸了。我甚至从未听说过使用三个反斜杠。这是我在Ubuntu 18上唯一有效的方法。有人可以解释一下为什么以及何时需要使用它吗?如果只用于scp,还是其他情况下也需要使用三个反斜杠而不是一个? - Joshua Pinter
2
请查看@AdrianGunawan的答案。它在本地主机上被转义一次,然后在远程主机上再次转义。因此,\\\_被转义一次以得到\_,然后再次转义以得到一个空格_。我使用_来清晰地表示一个空格。 - Ludovic Kuty

54

你也可以像这样做:

scp foo@bar:"\"apath/with spaces in it/\""

第一层引号将由scp解释,然后第二层引号将保留空格。


9
考虑到相同数量的转义字符可以处理多少空格,这个答案被低估了。谢谢! - Michael
1
非常被低估。不需要解析和修改路径!!! - biomiker
这应该是被接受的答案。更加简洁明了。 - undefined

29

当我尝试在Bash脚本中使用scp复制包含空格的远程路径时,遇到了类似的问题。

这里是我想出的解决方案:

手动转义路径:

scp user@host:'dir\ with\ spaces/file\ with\ spaces' <destination>
scp user@host:"dir\\ with\\ spaces/file\\ with\\ spaces" <destination>
scp user@host:dir\\\ with\\\ spaces/file\\\ with\\\ spaces <destination>

注意:不需要选项-T(请参见下文)。
使用双引号+选项-T
scp -T user@host:"'path with spaces'" <destination>
scp -T user@host:'"path with spaces"' <destination>
scp -T user@host:"\"path with spaces\"" <destination>

注意:如果不加选项-T,这些命令将会出现protocol error: filename does not match request的错误。具体原因可以在这里详细讨论。
使用Bash的printf转义路径:
source="path with spaces"
printf -v source "%q" "${source}"
scp user@host:"${source}" <destination>

用于Shell使用的一行命令:

source="path with spaces"; printf -v source "%q" "${source}"; scp user@host:"${source}" <destination>

注意:没有使用选项-T也能正常工作。

3
感谢您提供的printf解决方案。这是唯一一个对我有效的方法。我需要它用于源和目标。顺便说一下,可以使用“;”将所有内容放在同一行上。 - Slim Aloui
1
@SlimAloui 不用谢。好建议,我添加了一个printf替代方案的一行代码。 - Fonic

14

我很难让这个命令适用于一个包含空格的文件名的shell变量。由于某种原因,使用以下方式无法解决:

file="foo bar/baz"
scp user@example.com:"'$file'"

像 @Adrian 的答案一样似乎会失败。

事实证明,最好的方法是使用参数扩展来将反斜杠添加到空格前面,具体如下:

file="foo bar/baz"
file=${file// /\\ }
scp user@example.com:"$file"

1
我建议使用更强大的“全部替换”扩展: file="${file//\ /\\\ }" - troyfolger
我没有一个变量,但这对于一个有很多空格的路径来说是一个很好的替代品,这让我感到满意。没有人有时间处理那么多反斜杠! - Robert Dundon
1
@opello 不必转义空格。我已经修复了答案。 - Luke Davis
如果你非常不幸,文件名中既有反斜杠又有空格,那么首先转义反斜杠,然后再转义空格:file=${file//\\/\\\\};file=${file// /\\ } - cayhorstmann
对于我(在Ubuntu上),将引号放在变量内部可以使它正常工作:export file='"foo bar/baz"' ; scp user@example.com:"$file"。这样我就可以避免替换。也许这值得在答案中包含。 - Kjell
显示剩余3条评论

10

很抱歉在这个Linux问题中放置Windows 10 Powershell的技巧:在这种情况下,使用反斜杠转义空格或用引号包围空格无效。虽然不是很高效,但我使用"?"字符解决了它:

对于文件"tasks.txt Jun-22.bkp",我使用"tasks.txt?Jun-22.bkp"下载。


3
谢谢。我来这里寻找一个 Powershell 的解决方案,但以上的方法都不起作用,但这个方法可以。 - Dave Pile

9

scp ael5105@192.168.0.200:/home/5105/test/gg/Untitled?Folder/a/qy.jpg /var/www/try/

? 在远程执行通配符匹配,包括空格。


1
我真的很喜欢你,伙计。 - refex
1
这个!我正在连接到一个OpenSSH的Windows机器,而其他解决方案都没有起作用。 - Stewart

1

我是一个新手,使用的是Kali xD操作系统。以下是我的使用方法:如果你想要传输带有单个或多个空格的文件,从你的系统到远程服务器:

$ scp this\ is\ my\ file tryhackme@1.1.1.1:/home/tryhackme

请注意,IP地址只是一个示例,我输入的最后一个是目录和美元符号,这是提示符,代码以scp开头。
此外,您还可以指定在传输文件时要使用的名称,例如/home/tryhackme/file1或单个或多个空格,例如/home/tryhackme/"this\ is\ new\ file"
从远程服务器到您的系统,与上述相同,具有单个或多个空格:
$ scp tryhackme@1.1.1.1:/home/tryhackme/"remote\ server\ file" "this is mine now"

请注意,只有在要复制的文件中使用反斜杠\\,如您所见,字符串"this is mine now"没有\\,因为那是文件传输到我们系统时要使用的文件名,而不是我们想要安全复制(scp)的文件名。对不起,我的解释可能不太清楚,我希望有人能理解,我希望这能帮助需要另一种解决方案的人。

0
在 Linux 终端或 cmd 中,如果路径中的单词之间有空格,则必须使用引号('')("")标记。
你应该像这样做:
$ '/home/tryhackme'

不是

$ /home/tryhackme

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