我需要在单个 BASH 语句中执行以下操作。更喜欢的是,我有四个系统;我们称它们为 A、B、C 和 D。
系统 A 可以通过 SSH 连接到系统 B 和系统 C。
系统 B 可以通过 SSH 连接到系统 D。
从系统 A 运行以下命令:
ssh systemB "cd folder && (while true; do val1=\$(ssh systemD 'ls directory' | wc -l); val2=$(ssh systemC 'ls directory' | wc -l); echo "\$val1 \$val2"; if (( val1 == 0 && val2 == 0 )); then echo "Done"; break; fi; sleep 5; done;)"
循环第一次运行时似乎获得了正确的文件计数。当循环开始后两个目录中的文件计数发生变化时,val1
和的值val2
似乎保持不变。
答案1
如果systemB
不能ssh
,systemC
你就不能在那里有你的循环。它将必须从以下位置驱动systemA
:
until
val1=$(ssh -J systemB systemD "ls -q directory | wc -l")
val2=$(ssh systemC "ls -q directory | wc -l")
echo "$val1 $val2"
[ "$val1" -eq 0 ] && [ "$val2" -eq 0 ]
do
sleep 5
done
echo Done
还:
- 添加
-q
到ls
没有它你也可以计算文件名中的换行符。只要它只是检查数字是否非零,这里并不是真正的问题。 - 在远程进行计数 (
wc -l
) 以避免传输整个文件列表。 - 更清楚退出条件是什么。
- 使用
-J systemB
用作systemB
跳主持人。请注意,身份验证仍然使用凭据(ssh 代理或密钥)systemC
完成。systemA
要使用systemB
's,请执行:ssh systemB 'ssh systemD "ls -q directory | wc -l"'
。
您可以使用 which 在第一个匹配处停止,而不是计算文件数,ls | grep -q '^'
并且如果 systemD 上有文件,还可以避免 sshing 到 systemC:
while
ssh -J systemB systemD "ls -U directory | grep -q \^" ||
ssh systemC "ls -U directory | grep -q \^"
do
sleep 5
done
echo Done
(假设 GNUls
具有-U
跳过排序的选项,这意味着ls
可以在从目录读取文件名时开始输出文件名)
使用 ssh 控制套接字还可以避免在每次运行时进行昂贵的 ssh 连接和身份验证。
答案2
如果您编写像下面这样的代码,而不是一大堆单行代码,您会立即看到问题所在。
ssh systemB "cd folder &&
(while true; do
val1=\$(ssh systemD 'ls directory' | wc -l);
val2=$(ssh systemC 'ls directory' | wc -l);
echo "\$val1 \$val2";
if (( val1 == 0 && val2 == 0 )); then
echo "Done";
break;
fi;
sleep 5;
done;)"
您在 的行中\
缺少了。因此,是在完成时创建的,而不是作为循环的一部分。$
val2
val2
ssh systemB
因此,如果当您启动此命令时,$(ssh systemC 'ls directory' | wc -l)
值为 10,则循环将为
ssh systemB "cd folder &&
(while true; do
val1=\$(ssh systemD 'ls directory' | wc -l);
val2=10;
echo "\$val1 \$val2";
if (( val1 == 0 && val2 == 0 )); then
echo "Done";
break;
fi;
sleep 5;
done;)"