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会复制所有文件,但复制到同一个文件A.class

有任何想法吗? 谢谢!

使用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解释为一个空string,这使得目标名称为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)' . 

或者更复杂的shellpipe道导致文件名。 这不是一个安全问题,因为如果你可以连接scp,你可以连接到ssh。 但是这可能会让某些人更方便。

一个解决scheme是使用find来做到这一点:

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

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

我认为这是由于"${i}"被本地扩展到A$1.class ,然后被发送到扩展为A.class的远程,因为$1"" 。 你与此相处

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