【问题标题】:Bash read line stops in the middle of the file [duplicate]Bash读取行在文件中间停止[重复]
【发布时间】:2020-10-29 02:57:14
【问题描述】:

我创建了一个 bash 脚本来连接到多个服务器并执行一个程序。每个 IP 的 ips 和数量应从结构如下的配置文件中读取:

127.0.0.1 10
127.0.0.1 1
127.0.0.1 3

j=$((0))
while IFS=' ' read -r ip quantity; do
  echo "${ip} x ${quantity}";

  for (( i = 1; i <= quantity; i++ ))
  do
    echo "ssh root@${ip} cd test/libhotstuff && ./examples/hotstuff-app --conf ./hotstuff.gen-sec${j}.conf > log${j} 2>&1"
    ssh root@"${ip}" "cd test/libhotstuff && ./examples/hotstuff-app --conf ./hotstuff.gen-sec${j}.conf > log${j} 2>&1" &
    j=$((j+1))
  done

  sleep 1

done < ips

我注意到如果执行时间过长,这个 while 循环就会中断。如果我在这里休眠 1 秒,它将在第一次执行后停止。如果我删除它,但内部循环花费的时间太长,则不会读取行的子集。

这里有什么问题?

【问题讨论】:

  • 我不知道这是可能的 =D
  • BashFAQ 是天赐之物。另外,在编写代码之前值得阅读整个bash manual。你最终会节省时间和头痛。
  • 我调整了它,使脚本更清晰,谢谢。但问题依然存在。
  • 可能是我误解了“非交互式”的含义
  • 与此相关的 BashFaq 是 BashFaq #89

标签: bash shell ssh


【解决方案1】:

这是一个版本,它以 1 秒的延迟启动后台进程,等待 6 分钟,然后一个一个地杀死它们,每个之间有 1 秒的延迟,以使它们的运行时间大致相同。

您还应该向ssh 添加一些选项,以防止它干扰stdin 并在运行时过早终止循环。

  • -n
    防止从标准输入读取
  • -oBatchMode=yes
    密码短语/密码查询将被禁用
  • -oStrictHostKeyChecking=no
    即使主机密钥已更改也连接到主机
#!/bin/bash

sshopts=(-n -oBatchMode=yes -oStrictHostKeyChecking=no)

j=0
pids=()
while IFS=$' \t\n' read -r ip quantity; do
  echo "${ip} x ${quantity}";

  for (( i = 0; i < quantity; ++i ))
  do
    remotecmd="cd test/libhotstuff && ./examples/hotstuff-app --conf ./hotstuff.gen-sec${j}.conf > log${j} 2>&1"
    localcmd=(ssh ${sshopts[@]} root@${ip} "$remotecmd")
    echo "${localcmd[@]}"
    "${localcmd[@]}" &
    # store the background pid
    pids+=($!)
    (( ++j ))
    sleep 1
  done

done < ips

seconds=360
echo "running ${pids[@]} in the background $seconds seconds"

sleep $seconds

echo "telling the background processes to terminate"
for pid in ${pids[@]}
do
    echo killing $pid
    kill $pid
    sleep 1
done

echo "waiting for all the background processes to terminate"
wait
echo Done

【讨论】:

【解决方案2】:

这是一个将循环和并行进程卸载到远程 shell 脚本的版本。从带有数量的 HereDocument 生成远程 shell 脚本,并等待所有后台进程终止后再退出。

#!/usr/bin/env sh

while IFS=$' \t\n\r' read -r ip quantity || [ -n "$quantity" ]
do
  {
# When satisfied by the output:
# Ucomment the line below and delete its following line with the echo and cat
#    ssh "root@$ip" <<EOF
    echo ssh "root@$ip"; cat <<EOF
if cd test/libhotstuff
then
  i=$quantity
  until
    i=\$((i - 1))
    [ \$i -lt 0 ]
  do
    ./examples/hotstuff-app \\
      --conf "./hotstuff.gen-sec\$i.conf" >"log\$i" 2>&1 &
  done
  wait
fi
EOF
  } &
done <ips

# Wait for all child processes to terminate
wait
echo "All child ssh done!"

另一种通过使用数量参数调用的内联 shell 脚本替换动态 HereDocument 的方法:

#!/usr/bin/env sh

while IFS=$' \t\n\r' read -r ip quantity || [ -n "$quantity" ]; do
  echo ssh "root@$ip" sh -c '
if cd test/libhotstuff
then
  i=0
  while [ $i -lt "$1" ]; do
    ./examples/hotstuff-app --conf "./hotstuff.gen-sec$i.conf" >"log$i" 2>&1 &
    i=$((i + 1))
  done
  wait
fi
' _ "$quantity" &
done <ips

# Wait for all child processes to terminate
wait
echo "All child ssh done!"

【讨论】:

  • 这不起作用,因为我需要正在进行的变量 j 所以它是 conf${j} 而不是 conf${i}
  • @user2524707 您是否尝试运行仅打印通过 ssh 发送的内容的脚本?
  • 是的,我确实运行过它。工作顺利
猜你喜欢
  • 1970-01-01
  • 2021-03-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-20
  • 2013-03-07
  • 2018-08-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多