运行 一个 bash for 并行循环

run a bash for loop in parallel

我有这个脚本,它在本地保管库系统中为每个主机执行凭据查找,然后为其运行一个 ansible-playbook。

#!/bin/bash

for host in `cat ~/.ansible/hosts`
  do
    SECRET=`/opt/vault/bin/get-admin-credential --tag=$host`
    HOST=`echo $SECRET | cut -d ';' -f1`
    LOGIN=`echo $SECRET | cut -d ';' -f2`
    DOMAIN=`echo $SECRET | cut -d ';' -f3`
    PWD=`echo $SECRET | cut -d ';' -f4`

    if [ -z "$DOMAIN" ]; then
      ansible-playbook -i ~/.ansible/hosts ~/.ansible/windows.yml -e "ansible_host=$HOST ansible_user=$LOGIN ansible_password=$PWD" --limit $host
    else
      ansible-playbook -i ~/.ansible/hosts ~/.ansible/windows.yml -e "ansible_host=$HOST ansible_user=$LOGIN@$DOMAIN ansible_password=$PWD" --limit $host
    fi
  done

这会按顺序循环遍历每个主机,我已经尝试过使用 GNU parallel 但无法执行我想要的操作,运行 for 循环与 5 并行。

有人给我指点正确的方向吗?

我没有任何 "ansibles""vaults",所以这完全未经测试,但可能让你靠近:

doit(){
   host=""

   SECRET=$(/opt/vault/bin/get-admin-credential --tag=$host)
   HOST=$(echo $SECRET | cut -d ';' -f1)
   LOGIN=$(echo $SECRET | cut -d ';' -f2)
   DOMAIN=$(echo $SECRET | cut -d ';' -f3)
   PWD=$(echo $SECRET | cut -d ';' -f4)

   if [ -z "$DOMAIN" ]; then
      ansible-playbook -i ~/.ansible/hosts ~/.ansible/windows.yml -e "ansible_host=$HOST ansible_user=$LOGIN ansible_password=$PWD" --limit $host
   else
      ansible-playbook -i ~/.ansible/hosts ~/.ansible/windows.yml -e "ansible_host=$HOST ansible_user=$LOGIN@$DOMAIN ansible_password=$PWD" --limit $host
   fi
}

# Export doit function to subshells created by GNU Parallel
export -f doit

parallel -a ~/.ansible/hosts doit

在文体上,可能有一些改进。首先,由大写字母组成的shell变量是保留的,所以你不应该使用HOSTDOMAIN等。另外,你可以简化所有难看的切割和回显来提取通过使用 IFS=';'read 来自 SECRET 的变量,如下所示:

SECRET=$(/opt/vault/bin/get-admin-credential --tag=$host)
IFS=';' read host login domain pwd <<< "$SECRET"

所以,我最好也是最后的答案是:

doit(){
   host=""

   secret=$(/opt/vault/bin/get-admin-credential --tag=$host)
   IFS=';' read host login domain pwd <<< "$secret"

   if [ -z "$domain" ]; then
      ansible-playbook -i ~/.ansible/hosts ~/.ansible/windows.yml -e "ansible_host=$host ansible_user=$login ansible_password=$pwd" --limit $host
   else
      ansible-playbook -i ~/.ansible/hosts ~/.ansible/windows.yml -e "ansible_host=$host ansible_user=$login@$domain ansible_password=$pwd" --limit $host
   fi
}

# Export doit function to subshells created by GNU Parallel
export -f doit

parallel -a ~/.ansible/hosts doit

您只需要 运行 ansible-playbook 在后台使用 & 命令终止符。不过请注意,整个循环可以得到简化和改进。

run_playbook () {
  ansible-playbook -i ~/.ansible/hosts \
                   -e "ansible_host= ansible_login= ansible_password=" \
                   ~/.ansible/windows.yml --limit ""
}

while IFS= read -r host; do
    secret=$(/opt/vault/bin/get-admin-credential --tag="$host")
    IFS=";" read -r shost slogin sdomain spasswd _ <<< "$secret"
    if [[ -n $sdomain ]]; then
      login="$slogin@$sdomain"
    fi
    run_playbook "$host" "$shost" "$login" "$password" &
done < ~/.ansible/hosts