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

관련 정보