我有这个文件:
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}';