Bash 脚本等待多个服务器上的进程完成

Bash 脚本等待多个服务器上的进程完成

我想远程 ssh 到多个服务器并检查这些服务器上是否有任何进程正在运行,并等待该进程完成。我已经编写了下面的代码,但是自从我添加了“继续”语句以来,这只检查文件(ip.txt)中的第一个IP。我需要修改这段代码。

  while read IP
  do
    ssh ubuntu@$IP "pgrep -f pattern"
    if [ $? -eq 0 ]; then
       echo "Process is running" 
       sleep 10
       continue
    else
       echo "Process is not running"
    fi
  done < ip.txt

答案1

最好先对 IP 列表进行排序,然后对其进行迭代:

mapfile ipaddresses < ip.txt
canary=alive
while [[ "alive" == "$canary" ]]; do
  canary=dead
  for ip in ${ipaddresses[@]}; do
    if ssh ubuntu@$ip "pgrep -f pattern"; then
      echo "Process is running on $ip"
      canary=alive
      sleep 10
      continue
    else
      echo "Process not running on $ip"
    fi
  done
done

如果您仍然停留在低于 4 的版本bash,请将mapfile命令替换为:

read -r ipaddresses <<< "$( cat ip.txt )"

答案2

我在这里看到基本程序流程的一些问题。当你在这里有一个构造时,实际上有几件事被跟踪:

  1. 如果您列表中的任何主机在此检查中仍有正在运行的进程,我们应该记录下来并再次检查
  2. 如果仍然有进程的主机数量为 0,我们应该退出。

所以我会为此脚本使用两个循环。另外,continue这里不需要,这可能是导致它每次重复第一个主机的原因。

我做了一些不同的事情,主要测试返回的 PID 数量,psget而不是检查 ssh 退出代码,并使用一些稍微不同的语法。这是我想出的示例,它似乎适合您想要的内容:

#!/bin/bash
set -eu

# get number of IPs from lines in file
NUM_IPS=$( cat ip.txt | wc -l )
echo "checking ${NUM_IPS} hosts..."

# Set number of running hosts to the max.  While arbitrary, it will 
# update to the correct number before reporting, and if it is 0 the
# while loop will exit immediately.
IPS_STILL_RUNNING=${NUM_IPS}

while [ "${IPS_STILL_RUNNING}" -gt "0" ]
do
    RUNNING_NOW=0
    for IP in $( cat ip.txt )
    do
        PROC_NUM=$( ssh ${IP} -- pgrep -f pattern | wc -l )
        if [ "${PROC_NUM}" -gt "0" ]; then
            echo "  ${IP}: still running"
            RUNNING_NOW=$(( RUNNING_NOW + 1 ))
        else
            echo "  ${IP}: not running"
        fi
    done
    echo "still running on $RUNNING_NOW hosts"
    IPS_STILL_RUNNING=${RUNNING_NOW}
    sleep 10
done

答案3

如果您想并行连接多个主机,请使用类似(并行分布式 Shell)ssh的程序。pdsh

例如,如果您ip.txt包含 IP 地址而不是主机名,或者主机名和 IP 地址的混合:

hosts="$(awk '{l = l","$0}; END {sub(/^,/,"",l); print l}' ip.txt)"
while pdsh -l ubuntu -w "$hosts" 'pgrep -f pattern' 2>/dev/null | 
        grep pattern ; do
  sleep 10
done

这用于awk构建一个以逗号分隔的 IP 地址列表,以便通过ssh.

如果ip.txt文件包含仅有的主机名而不是IP地址,它更简单:

while pdsh -l ubuntu -F ./ip.txt -a 'pgrep -f pattern' 2>/dev/null | 
        grep pattern ; do
  sleep 10
done

这两者都假设ip.txt每行有一个 IP 地址或主机名。

循环while运行直到没有任何主机产量任何与模式匹配的输出。命令中的 stderr被重定向到 /dev/null,以避免当命令返回退出代码 1pdsh时向终端发送错误消息。pgreppdsh

唯一的输出来自grep pattern管道中。grep -q pattern如果您也希望使其静音,请使用。

相关内容