SCP 用美元符号覆盖文件

SCP 用美元符号覆盖文件

我有这个文件:

A.class
A$1.class
A$2.class

还有一个类似这样的 bash 脚本:

for i in *; do
    scp "${i}" foo@bar:/tmp/;
done

这很好。所有三个文件都已复制。问题在于以下方面:

for i in *; do
    scp "${i}" foo@bar:/tmp/"${i}";
    scp "${i}" foo@bar:"/tmp/${i}";
    scp "${i}" "foo@bar:/tmp/${i}";
done

在任何一种情况下,SCP 都会复制所有文件,但复制到同一个文件一类

有什么想法吗?谢谢!

答案1

使用scp -v显示有关 scp 如何工作的一些细节:

debug1: Sending command: scp -v -t /tmp/A$2.class
Sending file modes: C0644 0 A$2.class
Sink: C0644 0 A$2.class
A$2.class                                     100%    0     0.0KB/s   00:00    

本质上,由于 scp 通过 ssh 运行,它需要一个 shell 来执行你的命令,并且由于 没有$转义,远程 shell 会将其解释$2为空字符串,这使得目标名称为A.class

有两种方法可以解决这个问题。首先,你可以直接*在 scp 命令中使用 glob:

scp * foo@bar:/tmp/

但我很确定您还有其他需要使用循环的地方,因此这里介绍如何在循环中修复它:

for i in *; do
    scp "${i}" "foo@bar:'/tmp/${i}'"
done

检查现在的输出scp -v显示:

debug1: Sending command: scp -v -t '/tmp/A$2.class'

成功!单引号将阻止远程 shell 执行变量扩展。

更新:由于该参数被 shell 解释为一个参数,因此您可以执行以下操作:

scp foo@bar:'$(which ssh)' .

或者更复杂的 shell 管道,用于生成文件名。这是不是一个安全问题,因为如果你能用 scp 连接,你也能用 ssh 连接。但它可能会让某些人更方便。

答案2

一个解决方案是使用 find 来实现这一点:

find . -name A\*.class -print0|xargs -0 -i _PLACEHOLDER_ scp _PLACEHOLDER_ foo@bar:/tmp/_PLACEHOLDER_

这个想法是为了避免外壳扩张。

答案3

我认为这是由于"${i}"在本地将其扩展为A$1.class然后发送到远程将其扩展为A.class造成$1""。您可以使用

scp "${i}" foo@bar:/tmp/'${i}';

相关内容