Shell sai silenciosamente na expressão aritmética em loop

4

Eu escrevi um script para hosts remotos ssh, executei comandos, salvei a saída em arquivos e examinei as saídas. Mas sempre saia silenciosamente na linha (( success++ )) ao iterar o primeiro item na matriz workers . Se eu substituir (( success++ )) por echo "process $worker" , ele funcionará bem e imprimirá todos os hosts. Não consigo descobrir o que há de errado.

#!/bin/bash

set -x
set -e
workers=('host-1' 'host-2' 'host-3')

output_dir=$(mktemp -d)

for worker in ${workers[@]}; do
  ssh $worker '
    echo abc
    echo OK
  ' > "$output_dir/$worker" &
done

echo "waiting..."
sleep 3
wait

success=0
regexp='OK$'
for worker in ${workers[@]}; do
  output='cat "$output_dir/$worker"'
  if [[ "$output" =~ $regexp ]]; then
    (( success++ ))
  fi
done

echo "Total ${#workers[@]}; success: $success; failure: $((${#workers[@]} - success))"
    
por gzc 21.06.2017 / 08:52

2 respostas

7

Um exemplo simples deve explicar por que:

$ ((success++))
$ echo $?
1

O motivo é que qualquer operação aritmética que produz um valor numérico de zero retorna 1 . Eu não sei o que dizer - Bash tem o suficiente para o mundo todo.

    
por 21.06.2017 / 09:34
6

É a consequência de ter -e definido. Qualquer comando com um código de saída de 1 (não zero) acionará uma saída.

Este script funciona bem:

#!/bin/bash
(( success++))
echo "Still going 1 $success"

Isso não

#!/bin/bash
set -e
(( success++))
echo "Still going 1 $success"

Soluções

O mais simples é remover a linha set -e .

Se isso não for uma opção, use:

(( ++success ))

Outras alternativas:

#!/bin/bash

set -e
success=0
success=$(( success+1 ))
echo "still going 1 $success"

success=0
(( success=success+1 ))
echo "still going 2 $success"

success=0
(( success+=1 ))
echo "still going 3 $success"

success=0
(( ++success ))
echo "still going 4 $success"

success=0
(( success++ ))
echo "still going 5 $success"

Apenas a opção número 5 terá um código de saída de 1.

Outro (soluções mais complexas para qualquer valor da variável a ).
O primeiro usa os (POSIX) dois pontos ( : ) embutidos para torná-lo Compatível com POSIX.

: $(( a+=1 ))        ; echo "6 $a $?"   ## Valid Posix
   (( a++ )) || true ; echo "7 $a $?"
   (( a++ )) || :    ; echo "8 $a $?"
   (( a++ , 1 ))     ; echo "9 $a $?"
   (( a++ | 1 ))     ; echo "10 $a $?"
    
por 21.06.2017 / 12:03