Script de shell de manipulação de cadeia [duplicado]

2

Estou trabalhando em um projeto de UPS Monitoring usando o NUT Server. Meu objetivo é fazer um script de shell que envie um comando e, em resposta, receba o status e outros parâmetros do no-break.

por exemplo

#!/bin/bash
status='upsc myups' # command to get the status of UPS
sleep 1
exit 0

Isso está funcionando bem para mim, mas se eu declarar o 'status' como um array, a resposta dos ups é armazenada como um único elemento

ou seja,

#!/bin/bash
declare -a status #declare status as array
# command
status=$(upsc myups)  or status='upsc myups'
#number of array elements
echo ${status[@]}
exit 0

Número de elementos na matriz de status:

1

Saída de terminal / saída de matriz

echo ${#status[1]}

se eu fizer eco da matriz, a saída será semelhante à seguinte:

Init SSL without certificate database
battery.capacity: 9.00 battery.charge: 90 battery.charge.low: 20                                                                 
battery.charge.restart: 0 battery.energysave: no battery.protection: yes  
ups.shutdown: enabled ups.start.auto: yes ups.start.battery: yes   
ups.start.reboot: yes ups.status: OL CHRG ups.test.interval: 604800 
ups.test.result: Done and passed ups.timer.shutdown: -1     
ups.timer.start: -1   
ups.type: offline / line interactive ups.vendorid: 0463

Como essa saída inteira é salva em um único elemento da matriz "status". Estou tendo problemas para usar todos os parâmetros separadamente para fins de log.

Saída desejada:

battery.capacity: 9.00
battery.charge: 90 
battery.charge.low: 20                                                                 
battery.charge.restart: 0
battery.energysave: no 
battery.protection: yes

Como posso separar cada parâmetro em um elemento individual de uma matriz ou variável?

Por favor ajude

Obrigado

    
por Kunal Sonone 24.05.2016 / 22:58

4 respostas

1

Os dados que você recebe de upsc têm o formato keyword: value , um por linha. Você pode passar isso por meio de sed para obter o formulário [keyword]="value" e, em seguida, usar isso para inicializar um array associativo:

declare -A status="($(upsc myups | sed 's/\(.*\): \(.*\)/ []=""/'))"

Agora você pode obter o valor de qualquer palavra-chave, por exemplo, echo "${status[device.model]}" . Você pode percorrer todas as chaves e valores e fazer o que quiser:

for key in "${!status[@]}"
do    echo "$key: ${status[$key]}"
done

Note, se você citar seus valores,

status="$(upsc myups)"
echo "${status[@]}"

você ainda teria um valor único, mas cada valor estaria em uma nova linha, como na saída desejada.

    
por 24.05.2016 / 23:53
1

Você pode considerar:

upsc myups | grep -oP 'battery(\.\w+)+: \S+'

Sua principal necessidade é citar suas variáveis:

status=$(upsc myups)
echo "$status"
    
por 24.05.2016 / 23:36
0

Você pode usar readarray bash builtin:

readarray status < <(upsc myups)
    
por 24.05.2016 / 23:21
0

A solução mais simples é atribuir uma matriz (ou seja, entre parênteses) em vez de uma string a $status .

Defina também o IFS como uma nova linha ( \n ) para que cada linha (em vez de cada palavra) seja inserida em um elemento de matriz separado:

$ IFS=$'\n' status=( $(upsc myups 2>/dev/null | grep '^battery\.') )

$ printf "%s\n" "${status[@]}"
battery.capacity: 9.00
battery.charge: 90
battery.charge.low: 20
battery.charge.restart: 0
battery.energysave: no
battery.protection: yes

$ declare -p status   # reformatted slightly for readability.
declare -a status='([0]="battery.capacity: 9.00" [1]="battery.charge: 90"
                    [2]="battery.charge.low: 20" [3]="battery.charge.restart: 0"
                    [4]="battery.energysave: no" [5]="battery.protection: yes")'

PS: Se você fizer um processamento significativamente maior com esses valores upsc , recomendo usar perl ou awk ou python em vez de bash - eles são muito mais adequados para escrever ferramentas complexas de processamento de texto do que bash sozinho.

    
por 25.05.2016 / 08:06