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