如何在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,因此沒有任何內容前置,對於其餘行,$notfirst為 1,因此打印換行符,對於最後一行,加法給出 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

相關內容