키=값 블록을 CSV로 변환

키=값 블록을 CSV로 변환

한 파일의 내용을 다른 파일로 바꾸려고 합니다.

입력 파일 Test.txt:

HLRSN = 3
IMSI = 404212109727229
KIVALUE = A24AD11812232B47688ADBF15CE05CA9
K4SNO = 1
CARDTYPE = SIM
ALG = COMP128_3

HLRSN = 3
IMSI = 404212109727230
KIVALUE = A24AD11812232B47688ADBF15CE05CB8
K4SNO = 1
CARDTYPE = SIM
ALG = COMP128_3

HLRSN = 3
IMSI = 404212109727231
KIVALUE = A24AD11812232B47688ADBF15CE05CD6
K4SNO = 1
CARDTYPE = SIM
ALG = COMP128_3

다른 텍스트 파일에서 원하는 출력:

3,404212109727229,A24AD11812232B47688ADBF15CE05CA9,1,SIM,COMP128_3
3,404212109727230,A24AD11812232B47688ADBF15CE05CB8,1,SIM,COMP128_3
3,404212109727231,A24AD11812232B47688ADBF15CE05CD6,1,SIM,COMP128_3

답변1

간단히:

awk -v RS= -v OFS=, '{print $3,$6,$9,$12,$15,$18}'

비어있는기록 구분 기호( RS=) 할 수 있게 하다단락 모드여기서 레코드는 일련의 빈 줄로 구분됩니다. 레코드 내부에는 기본 필드 구분 기호가 적용되므로(레코드는 공백으로 구분됨) 각 레코드에서 관심 있는 필드는 3번째, 6번째, 9번째...

우리는 변한다산출필드 구분 기호는 쉼표 문자( OFS=,)이며 관심 있는 필드를 인쇄합니다.

답변2

일방 bash통행:

declare -a out

EOF=false
IFS=$'='

until $EOF; do
  read -r skip val || EOF=true
  if [ ! -z "$val" ]
  then
    out+=("${val//[[:space:]]/}")
  else
    tmp="${out[@]}"
    printf '%s\n' "${tmp// /,}"
    out=()
  fi
done < file

어떻게 작동하나요?

  • out출력 라인을 보관할 배열을 선언하고 , EOF파일 끝을 추적하도록 변수를 설정하고, IFS입력 필드 구분 기호를 사용합니다 read.
  • 파일의 끝을 읽을 때까지 파일의 각 줄을 읽고 마지막 필드의 값을 변수로 설정합니다 val.
  • if [ ! -z "$val" ]: 변수의 길이가 $val0이 아닌지 확인하기 위해 공백을 제거 $val하고 배열에 푸시합니다 out.
  • 길이가 $val0이면, 즉 빈 줄이나 파일 끝이 표시되면 배열의 모든 요소를 out​​변수 tmp에 할당한 다음 모든 공백 변수를 우리가 설계한 출력 기록 구분 기호 tmp로 바꿉니다.,
  • out추가 작업을 위해 null로 설정하세요 .

또 다른 깨끗하고 짧은 솔루션은 다음을 사용하는 것입니다 perl.

$ perl -F'=' -anle '
    BEGIN { $, = "," }
    push @out,$F[-1] if @F;
    print @{[map {s/\s// && $_} @out]} and @out = ()
        if /^$/ or eof;
' file
3,404212109727229,A24AD11812232B47688ADBF15CE05CA9,1,SIM,COMP128_3
3,404212109727230,A24AD11812232B47688ADBF15CE05CB8,1,SIM,COMP128_3
3,404212109727231,A24AD11812232B47688ADBF15CE05CD6,1,SIM,COMP128_3

답변3

다음을 파일에 저장합니다(예 split.awk: ).

BEGIN {
RS="\n\n";
FS="\n";
ORS=",";
}

{
    for (i=1;i<=NF;i++)
    {
        split($i, sf, "= ")
        print sf[2]
    }
    printf "\n"
 }

그런 다음 다음을 실행하십시오.

awk -f split.awk Test.txt

또는 전체 명령을 한 줄로 실행합니다.

awk 'BEGIN {RS="\n\n";FS="\n";ORS=",";}{for(i=1;i<=NF;i++){split($i, sf, "= ")print sf[2]}printf "\n"}' Test.txt

작동 방식은 다음과 같습니다.

  • 블록은 BEGIN처음에 한 번 실행되며 레코드 구분 기호( RS)를 두 개의 줄 바꿈으로 설정하고 필드 구분 기호( FS)를 단일 줄 바꿈으로 설정합니다. 출력 레코드 구분 기호( ORS)는 쉼표로 설정됩니다.

  • 그런 다음 레코드의 각 필드( NF현재 레코드의 필드 수)를 반복하고 "="로 분할합니다.

  • ORS그런 다음 각 분할 사이에 쉼표( ) 를 사용하여 해당 분할의 오른쪽을 인쇄합니다.

  • 각 줄 뒤에 개행 문자가 인쇄되어 CSV 형식을 제공합니다.

답변4

사용밀러( mlr) 우리는 단일 줄 바꿈으로 구분된 필드를 포함하고 등호로 구분된 키-값 쌍을 포함하는 이중 줄 바꿈으로 구분된 레코드로 데이터를 읽을 수 있습니다. 추가 공백과 빈 열(이러한 구분 기호를 사용하여 데이터를 읽은 결과 각 필드 값의 시작 부분에 공백이 추가됨)을 제거한 다음 이를 CSV로 변환할 수 있습니다.

$ mlr --ips = --ifs lf --irs lflf --ocsv clean-whitespace then remove-empty-columns Test.txt
HLRSN,IMSI,KIVALUE,K4SNO,CARDTYPE,ALG
3,404212109727229,A24AD11812232B47688ADBF15CE05CA9,1,SIM,COMP128_3
3,404212109727230,A24AD11812232B47688ADBF15CE05CB8,1,SIM,COMP128_3
3,404212109727231,A24AD11812232B47688ADBF15CE05CD6,1,SIM,COMP128_3

출력에 CSV 헤더를 포함하지 않으려면 이 옵션을 mlr함께 사용하십시오 -N. Miller는 포함된 구분 기호나 따옴표가 포함된 모든 필드를 자동으로 인용합니다.

관련 정보