Как разделить строку на массив в 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

Связанный контент