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 + last0이므로 앞에 아무것도 추가되지 않습니다. 나머지 줄에서는 $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

관련 정보