web-dev-qa-db-ja.com

文字列操作シェルスクリプト

NUTサーバーを使用してUPS監視プロジェクトに取り組んでいます。私の目的は、1つのコマンドを送信し、それに応じてUPSからステータスやその他のパラメーターを受信するシェルスクリプトを作成することです。

例えば

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

これは私にとっては問題なく機能していますが、「status」を配列として宣言すると、upsからの応答は単一の要素として保存されます

つまり.

#!/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

ステータス配列の要素数:

1

端末出力/配列出力

echo ${#status[1]}

配列をエコーすると、出力は次のようになります。

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

この出力全体が「ステータス」配列の単一の要素に保存されるため。ログの目的ですべてのパラメーターを個別に使用すると問題が発生します。

目的の出力:

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

各パラメーターを配列または変数の個々の要素に分割するにはどうすればよいですか?

助けてください

ありがとうございました

2
Kunal Sonone

upscから返されるデータは、1行に1つずつ、keyword: valueの形式です。これをsedに渡して[keyword]="value"の形式を取得し、これを使用して連想配列を初期化できます。

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

これで、echo "${status[device.model]}"などの任意のキーワードの値を取得できます。すべてのキーと値をループして、必要なことを実行できます。

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

値を引用する場合は、

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

まだ単一の値を取得しますが、各値は、目的の出力のように新しい行にあります。

1
meuh

あなたは考えるかもしれません:

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

あなたの主な必要性はあなたの変数を引用することです:

status=$(upsc myups)
echo "$status"
1
glenn jackman

readarraybash組み込みを使用できます。

readarray status < <(upsc myups)
0
adonis

最も簡単な解決策は、$statusに文字列ではなく配列(つまり、括弧で囲まれている)を割り当てることです。

また、IFSを改行(\n)に設定して、各行(各Wordではなく)を個別の配列要素に配置します。

$ 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:これらのupsc値を使用して大幅に多くの処理を行う場合は、Perlの代わりにawkまたはpythonまたはbashを使用することを強くお勧めします。これらはすべて、bashだけの場合よりも、複雑なテキスト処理ツールの作成にはるかに適しています。

0
cas