Como definir os elementos da matriz vazia como zero?

0

Estou escrevendo um script que envia o resultado de comandos para uma matriz de saída. Envolve a verificação de logs e a recuperação de seus servidores, mas há casos em que o servidor tem um host de failover. Nesses casos, preciso que o script verifique os dois hosts e retorne os valores. O problema que estou correndo é se qualquer um dos elementos da matriz de saída está vazio (o que significa que não há arquivo existente no servidor para verificar, retornando apenas um espaço em sua respectiva exibição de eco), ele causa uma mudança nos índices da matriz. Isso significa que o que deve estar no conjunto de matriz do host secundário é esbarrado no primário. Em vez disso, gostaria de ter esses índices vazios armazenados como 0 como um espaço reservado para evitar que a mudança ocorra. É aqui que o deslocamento do índice é aparente:

echo The primary overall log value is ${output[0]}.
echo The primary obs log value is ${output[2]}.    
echo The primary tracks log value is ${output[4]}.  
echo
echo The secondary overall log value is ${output[6]}.
echo The secondary overall log value is ${output[8]}.
echo The secondary overall log value is ${output[10]}.

O que acontece por exemplo é que se as saídas [2] e [4] estiverem vazias, a saída [6] irá mudar para a linha correspondente à saída [2]. Eu tentei esta solução, mas sem sorte:

  s=0

  for x in "${output[@]}"
     do(
     x=
        if [[ -z $x ]];
        then(
        x=0
        echo $x)
        else echo
        fi
     s=s+1)
 done

Tudo isso faz cuspir zeros antes que ocorra o eco das saídas e não se ajusta a nenhum deslocamento de índice.

Observação: é de onde vem o array de saída, junto com uma tentativa de correção abaixo dele:

for h in "${host[@]}"
do
    for path in "${paths[@]}"
    do
            output+=( $(ssh $h du -sh $path) )
            for x in "${!output[@]}";
            do(
                    if [[ -z "${output[$x]}" ]];
                    then output[$x]=0;
                    fi;
            )
            done

    done
done

Onde host e caminho já estão definidos matrizes. Eu também observaria que o script funciona bem para os casos em que há apenas um host para acessar, e não há nenhum problema com os índices de matriz.

    
por MLopes7 17.07.2018 / 20:36

1 resposta

2

What happens for example is if output[2] and [4] are empty, output[6] will shift up to the line corresponding to output [2].

Nesse caso, você não tem valores vazios no lugar de 2 e 4, é apenas que você tem menos valores do que o esperado.

Considere as atribuições da matriz:

array1=(a b c d)
array2=(A D)

O primeiro define array1[0] a a , array1[1] a b etc. O segundo define array2[0] a A e array2[1] a D . Não há como saber se deveria haver valores vazios entre A e D . Eles precisariam estar na tarefa explicitamente:

array2=(A "" "" D)

Você provavelmente está preenchendo o array output de alguma outra forma, mas como você não mostra como é feito, não há como comentá-lo. Você provavelmente tem um caso semelhante ao acima: os valores "vazios" não são vistos como valores por qualquer que seja o preenchimento da matriz output .

Se você está atribuindo a matriz a partir de uma expansão e confiando na divisão de palavras, não é possível evitar isso. (Mesmo se IFS contiver apenas nova linha, ele irá dobrar novas linhas vazias consecutivas para uma, removendo linhas vazias). Se você estiver usando mapfile , as linhas vazias devem aparecer como elementos da matriz por padrão.

Em qualquer caso, seu loop para zero elementos de array vazios não funciona porque você não atribui ao array dentro do loop (de jeito nenhum), e mesmo se você o fez, o corpo do loop é executado em um subshell (como marcado pelo parêntese (...) ), portanto, quaisquer atribuições não ocorreriam fora do corpo do loop, de qualquer forma.

Você não pode realmente usar um for x in "${output[@]}" para modificar os elementos da matriz, já que x obtém apenas uma cópia dos valores da matriz, modificando-a não altera os originais. Você precisaria percorrer os índices da matriz para poder apontar para a matriz:

somearray=(1 "" "" 4)
for i in "${!somearray[@]}"; do
    if [[ -z "${somearray[$i]}" ]]; then
        somearray[$i]=0;
    fi;
done
echo "${somearray[@]}"

imprime 1 0 0 4 .

Em seu código de amostra adicionado, a atribuição output+=( $(ssh $h du -sh $path) ) não adicionará nenhum elemento vazio. Os caminhos ausentes serão apenas omitidos da matriz. Considere que primeiro, du $path não imprime nada se o caminho não existir. (Além de um erro, mas que vai para stderr, e não é capturado pela substituição de comando.) Além disso, mesmo que tenha sido impressa uma linha vazia (ou espaços / tabulações), a divisão de palavras remove espaços em branco consecutivos.

Experimente, por exemplo array=( $( printf "foo\n\nbar\n" ) ) , cria uma matriz de dois elementos.

Além disso, os parênteses no loop de substituição iniciam um subshell, portanto, quaisquer modificações no array só entrarão em vigor dentro desse subshell. Em geral, você não quer agrupar comandos shell com parênteses, a menos que você saiba que você quer uma subshell em particular.

Você pode colocar aspas ao redor da substituição do comando ( "$(ssh ... du)" ) para ter certeza de obter exatamente uma string, mas provavelmente você quer separar o tamanho do nome do caminho.

Tente algo assim para coletar os caminhos e seus tamanhos em uma única matriz:

for host in "${hosts[@]}"; do
    for path in "${paths[@]}"; do
        output="$(ssh "$host" du -sh "$path")"
        size="${output%%$'\t'*}"           # needs Bash/ksh/zsh
        size="${size:-0}"
        sizes+=( "$size" "$host:$path"  )
    done
done

Agora, todo elemento de matriz uniforme contém um tamanho e todo ímpar, o nome de host e o caminho correspondentes, um pouco parecido com o que resultaria na divisão da saída de du . As expansões de dois parâmetros de output e size remova tudo após uma tabulação e substitua o tamanho por zero, se estiver vazio.

Como alternativa, você pode criar uma matriz associativa , indexada pelo host + caminho:

declare -A array
...
    array["$host:$path"]=$size
    
por 17.07.2018 / 21:11