Bashで文字列を配列に分割する方法

Bashで文字列を配列に分割する方法

私のプログラムの出力に問題があります。 Bashからコマンドを起動し、対応する出力(文字列)を取得して分割して、特定の場所に新しい行を追加する必要があります。文字列は次のとおりです。

battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500

基本的にxxx.yy.zz:値ですが、値にスペースを含めることができます。これが私が得たい結果です

battery.charge: 90
battery.charge.low: 30
battery.runtime: 3690
battery.voltage: 230.0
device.mfr: MGE UPS SYSTEMS
device.model: Pulsar Evolution 500 

最初のポイントを検索してから、その場所から新しい行を配置するスペースを見つけるというアイデアがありますが、Bashでこれを実装する方法がわかりません。

答え1

純粋なbashソリューション、文字列処理に使用される外部ツールなし、パラメータ拡張のみ可能:

#! /bin/bash
str='battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500'

IFS=: read -a fields <<< "$str"

for (( i=0 ; i < ${#fields[@]} ; i++ )) ; do
    f=${fields[i]}

    notfirst=$(( i>0 ))
    last=$(( i+1 == ${#fields[@]} ))

    (( notfirst )) && echo -n ${f% *}

    start=('' $'\n' ' ')
    colon=('' ': ')
    echo -n "${start[notfirst + last]}${f##* }${colon[!last]}"
done
echo

説明:$notfirst合計は$lastブール値です。最初のフィールドは、最後のスペースの前の部分を印刷しません。${f% *}なぜならそんなことがないからです。$startそして、$colonフィールドを区切るさまざまな文字列を保存します。最初の項目notfirst + lastは0なので、前に何も追加されません。残りの行は$notfirst1 であるため、改行が印刷され、最後の行に追加すると 2 が表示されます。スペースが印刷されます。次に、最後のスペースの後の部分を印刷します${f##* }。コロンは、最後の行を除くすべての行に印刷されます。

答え2

GNU sedを使用すると、空白なしで終わるすべての連続した文字列を見つけ、最初の文字:列を除くすべての文字列の前に改行文字を入れることができます。

sed 's/[^[:space:]]\+:/\n&/g2'

あなたのsedバージョンが拡張機能をサポートしていない場合は、通常の修飾子をgn使用できますg

sed 's/[^[:space:]]\{1,\}:/\
&/g'

最初のキーの前に追加の改行を印刷する以外は同じ方法で動作します。perl -pe 's/\S+:/\n$&/g'同じ条件を使用できます(GNU sedと同等のperlがあるかもしれませんが、g2私はそれを知りません)。

答え3

一方perl通行:

$ perl -pe 's{\S+:}{$seen++ ? "\n$&" : "$&"}ge' file
battery.charge: 90 
battery.charge.low: 30 
battery.runtime: 3690 
battery.voltage: 230.0 
device.mfr: MGE UPS SYSTEMS 
device.model: Pulsar Evolution 500

説明する

  • \S+:一致文字列は:
  • 一致するすべての文字列の前に改行文字を挿入します(("\n$&")最初の文字列を除く)($seen++)

答え4

これは、入力のタブと改行(ある場合)が通常の空白に変換されることを気にしないという仮定で動作する簡単なアプローチです。

アイデアは簡単です。入力を空白に分割し、:改行文字で終わるトークンを除くすべてのトークンを印刷します(そして他のトークンの前に空白を再追加します)。変数$countと関連変数は、if最初の空白行を防ぐためにのみ使用されます。問題がなければ削除してください。 (スクリプトは、入力がintput現在ディレクトリから呼び出されたファイルにあると仮定します。)

#! /bin/bash

count=0
for i in $(<input) ; do
   fmt=
   if [[ $i =~ :$ ]] ; then
       if [[ $count -gt 0 ]] ; then
           fmt="\n%s"
       else
           fmt="%s"
       fi
       ((count++))
   else
       fmt=" %s"
   fi
   printf "$fmt" "$i"
done
echo
echo "Num items: $count"

誰かがより良いオプションを思いつくことができることを願っています。

$ cat input
battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500
$ ./t.sh
battery.charge: 90
battery.charge.low: 30
battery.runtime: 3690
battery.voltage: 230.0
device.mfr: MGE UPS SYSTEMS
device.model: Pulsar Evolution 500
Num items: 6

関連情報