访问远程机器时如何在 heredoc 中运行 for 循环

How to run for loop inside heredoc while accessing remote machine

提问人:Ashutosh 提问时间:9/23/2018 最后编辑:Ashutosh 更新时间:9/24/2018 访问量:878

问:

这是我的脚本,其中我使用远程计算机中的局部变量。但是 下的循环只接受第一个变量值。循环在 内部运行良好,但具有相同的值。heredocheredocheredoc

#!/bin/bash
prod_web=($(cat /tmp/webip.txt));
new_prod_app_private_ip=($(cat /tmp/ip.txt));
no_n=($(cat /tmp/serial.txt));
ssh -t -o StrictHostKeyChecking=no ubuntu@${prod_web[0]} -p 2345 -v << EOF
set -xv
for (( x = 0; x < '${#no_n[@]}'; x++ ))
do
sudo su
echo '${no_n[x]}'
echo '${new_prod_app_private_ip[x]}'
curl -fIkSs https://'${new_prod_app_private_ip[x]}':9002 | head -n 1 
done
EOF

因此,我的 ip.txt 文件包含以下值:

10.0.1.0
10.0.2.0
10.0.3.0

我的serial.txt文件:

9
10
11

因此,我的循环仅针对远程机器中的第一个 IP(存在于 中)运行了三次。我想为所有三个 IP 运行它。我的远程 IP 存在于文件中。/tmp/ip.txt/tmp/webip.txt

被卡住了很长时间,任何帮助都是值得赞赏的。我还有其他解决方案吗?

bash 循环变量 eof heredoc

评论

0赞 KamilCuk 9/23/2018
这里 doc 不运行任何命令,除了命令替换和变量扩展。这就像.您希望循环在本地计算机还是远程计算机上执行?echo heredoc
0赞 Ashutosh 9/23/2018
@KamilCuk 我希望在远程计算机上执行循环。
0赞 that other guy 9/24/2018
要对此进行调试,请替换为并查看远程主机看到的内容。ssh ...cat
0赞 Ashutosh 9/24/2018
@thatotherguy我已经设置了 -xv,还需要吗?
0赞 that other guy 9/24/2018
没有人需要任何东西,但如果你看一下你要求主机运行的脚本,就会立即明白为什么它的行为方式是这样的。

答:

2赞 KamilCuk 9/24/2018 #1

有 2 种环境。在本地计算机和远程计算机上。您需要考虑如何在这些机器之间传输数据/变量/状态/对象/句柄。 如果您在本地计算机上设置了某些内容(即),然后只是通过 ssh 连接到远程主机(即),则该变量将不可见/导出到远程计算机。您可以:prod_web=($(cat /tmp/webip.txt));ssh user@host 'echo "${prod_web[@]}"'

  • scp 文件 {ip,serial}.txt并在远程计算机上执行整个脚本,然后清理 ,即。从远程计算机中删除 {ip,serial}.txt 文件
  • 以某种方式合并/加入/粘贴的文件 {ip,serial}.txt传递到 SSH 的 stdin,然后在删除计算机上读取 stdin
  • 创建要在本地计算机上运行的所有命令,然后将预先准备好的命令传递到远程计算机,例如ssh .... "$(for ...; do; echo curl ...; done)"

我会选择第二种选择,因为我喜欢使用管道传递所有内容,并且不喜欢在我之后进行清理 - 在出错时删除临时文件可能会一团糟。

我的脚本可能如下所示:

#!/bin/bash 
set -euo pipefail
read -r host _ <webip.txt
paste serial.txt ip.txt | ssh -t -o StrictHostKeyChecking=no -p 2345 -v ubuntu@"$host" '#!/bin/bash
set -euo pipefail
while read -r no_n ip; do
     for ((i = 0; i < no_n; ++i)); do
         printf "%s\n" "$no_n"
         printf "%s\n" "$ip"
         curl -fIkSs https://"$ip":9002 | head -n 1 
      done
done
'

由于远程脚本会变得更大并且对 qouting 不太友好,我会将其保存到另一个脚本中并执行。
我不明白你想用它做什么,这 100% 不会做你想做的。
如果幻数是执行该 curl 的次数,并且您有 xargs 并且您并不真正关心错误,那么您可以做一个神奇且令人困惑的单行:
remote_scripts.shssh ... -m remote_scripts.shsudo suno_n

#!/bin/bash 
set -euo pipefail
read -r host _ <webip.txt
paste serial.txt ip.txt | ssh -t -o StrictHostKeyChecking=no -p 2345 -v ubuntu@"$host" 'xargs -n2 -- sh -c "seq 0 \"\$1\" | xargs -n1 -- sh -c \"curl -fIkSs https://\\\"\\\$1\\\":9002 | head -n 1\" -- \"\$2\"" --'

准备所有要运行的命令实际上可能更具可读性,并且可能会节省一些令人讨厌的问题来解决。但这实际上取决于serial.txt和ip.txt有多大,以及要在远程计算机上执行的命令有多大,因为您希望最大限度地减少在计算机之间传输的字节数。
这里要运行的命令是在本地机器上构造的(即。“$(...)” 被传递给 ssh) 并在远程计算机上执行:

# semi-readable script, not as fast and no xargs
ssh -t -o StrictHostKeyChecking=no -p 2345 -v ubuntu@"$host" "$(paste serial.txt ip.txt | while read -r serial ip; do 
   seq 0 "$serial" | while read -r _; do
         echo "curl -fIkSs \"https://$ip:9002\" | head -n 1"
   done

完成)”

HERE-doc 不会展开 shell 命令,因此:

$ cat <<EOF
> echo 1
> EOF
echo 1

但是您可以使用命令替换:$( ... )

$ cat <<EOF
> $(echo 1)
> EOF
1

评论

1赞 Ashutosh 9/24/2018
由于时间紧迫,我没有尝试过解决方案,我使用了答案中提到的命令,这节省了我的一天。将在不久的将来实施。感谢所有的帮助。paste