여러 줄의 레코드를 "값" 부분만 포함하는 단일 CSV 행으로 축소합니다.

여러 줄의 레코드를 "값" 부분만 포함하는 단일 CSV 행으로 축소합니다.

아래와 같이 여러 행의 기록된 데이터가 있습니다.

Name>Ami  
Admin>2  
Oper>1  
Name>Sum  
Admin>3  
Total>2  
Name>Tar  
Admin>1  
Oper>2

Name이제 이러한 레코드를 레코드 요소 와 Admin'값' 부분 만 포함하는 단일 CSV 행으로 축소하려고 합니다 Oper. 이 예의 경우 최종 출력은 다음과 같아야 합니다.

Ami,2,1  
Sum,3,
Tar,1,2  

출력을 얻을 수 있지만 해당 값을 일치시켜 첫 번째와 두 번째 열에 넣은 다음 세 번째 열에 넣고 paste - - - -d,싶기 때문에 사용하고 싶지 않습니다 .NameAdminOper

답변1

당신이 원하는 것 같습니다

  • 여러 레코드 행을 단일 CSV 행으로 축소합니다.
  • 레코드 속성의 값만 인쇄 합니다 Name.AdminOper
  • 이러한 속성 중 하나가 제공되지 않은 "명시적" 빈 필드를 인쇄합니다.

나는 다음 awk프로그램을 추천하고 싶습니다:

awk -F'>' 'function printrec(){printf "%s,%s,%s\n",buf["Name"],buf["Admin"],buf["Oper"]}
           (FNR>1 && $1=="Name"){printrec();delete buf}
           {sub(/[[:space:]]*$/,"",$2); buf[$1]=$2}
           END{printrec()}' input.txt

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

  • 입력 파일의 필드 구분 기호는 으로 설정됩니다 >.

  • 레코드의 모든 요소는 연관 배열에 저장됩니다 buf.

  • printrec()관련 필드를 쉼표로 구분하여 인쇄하는 함수가 정의됩니다 . 특정 키가 포함되지 않은 buf경우 buf참조는 빈 문자열로 평가되어 누락된 속성에 대한 빈 필드에 대한 요구 사항을 충족합니다.

  • 레코드가 line 으로 시작한다고 가정합니다 Name. 이와 같은 줄을 만나면아니요파일의 첫 번째 줄( FNR>1)은 이전에 버퍼링된 레코드를 인쇄하고 버퍼를 다시 지웁니다.

  • buf각 행에 대해 현재 속성은 "배열 인덱스"로 "키" 부분을, 배열 값으로 "값" 부분을 사용하여 저장됩니다 .

    노트sub()입력 예제에 포함된 "값" 부분에서 후행 공백을 제거하는 호출을 포함했습니다 . 실제로 공백이 없다고 확신한다면 3행의 해당 부분은 생략해도 됩니다.

  • 파일 끝에서 최종 버퍼링된 레코드가 인쇄됩니다.

이 절차를 예제에 적용하면 다음과 같은 결과가 나타납니다.

Ami,2,1
Sum,3,
Tar,1,2

노트delete배열을 사용하려면 GNU가 필요합니다 awk. 맛이 다양하다면 awk꼭 사용해보세요

split("",buf)

해결 방법으로.

또한 레코드에 속성의 여러 인스턴스가 포함되어 있는 경우( Name항상 레코드의 시작으로 간주되지 않는 한) 후속 발생은 이전 발생을 덮어씁니다.

답변2

원하는 것이 무엇인지 이해했다면 다음을 사용 xargs하고 awk명령해야 합니다.

xargs -n3 < your_file.txt  | awk  '{gsub(/(Name|Admin|Oper)>/,"");  print $1","$2","$3}' | awk -F',' --file script.awk

script.awk이를 포함할 위치 :

#! /usr/bin/awk

{
   if($1 ~ ".*>.*") print ","$2","$3 
   else if($2 ~ ".*>.*") print $1",,"$3 
   else if($3 ~ ".*>.*") print $1","$2"," 
   else print
}

당신이 가지고 있다면 your_file.txt:

Name>Ami  
Admin>2  
Oper>1  
Name>Sum  
Admin>3  
Total>2  
Name>Tar  
Admin>1  
Oper>2

xargs -n33줄마다 파일의 출력을 한 줄로 얻을 수 있습니다 .

Name>Ami Admin>2 Oper>1
Name>Sum Admin>3 Total>2
Name>Tar Admin>1 Oper>2

awk '{gsub(/(Name|Admin|Oper)>/,""); print $1","$2","$3}'이와 같은 값 으로이름 > 관리자 > 또는 운영자 >은 빈 문자열로 대체되고 print $1","$2","$3(> 뒤의) 값은 쉼표와 함께 인쇄됩니다.

다음을 사용하는 경우:

xargs -n3 < data3  | awk  '{gsub(/(Name|Admin|Oper)>/,"");  print $1","$2","$3}

당신은 얻을 것이다:

Ami,2,1
Sum,3,Total>2
Tar,1,2

이제 불필요한 문자열을 제거합니다 Total>2. 예를 들어 script.awk를 사용하여 제거할 수 있지만 그 전에 구분 기호(이 경우 쉼표)를 정의해야 합니다 ,. 이와 같은 Awk 코드는 $1 ~ ".*>.*"현재 문자열($1, $2 또는 $3)이 패턴과 일치하는지 확인 .*>.*하고 일치하는 경우 현재 문자열은 인쇄되지 않습니다.

중요한:작품은 script.awk그룹 형식으로 발표됩니다. 따라서 유효하지 않은 열이 있으면 대신 이 열을 넣어야 합니다.이름또는행정또는오페라. 예를 들어 다음과 같은 경우가 your_file.txt있습니다.

Name>Ami  
Total>2  
Oper>1  
Name>Sum  
Admin>3  
Total>2  
Total>Tar  
Admin>1  
Oper>2

이 스크립트의 출력은 다음과 같습니다.

Ami,,1
Sum,3,
,1,2

하지만 다음과 같은 경우 your_file.txt:

Total>Ami  
Total>2  
Oper>1  
Name>Sum  
Admin>3  
Total>2  
Total>Tar  
Admin>1  
Total>2

이 명령은 예상대로 작동하지 않습니다.

노트:편집하고 싶다면 마지막에 다음을 사용해야 your_file.txt합니다 .tee your_file.txt

xargs -n3 < your_file.txt  | awk  '{gsub(/(Name|Admin|Oper)>/,"");  print $1","$2","$3}' | awk -F',' --file script.awk | tee your_file.txt

답변3

[기록이 가끔 누락되는 경우가 있는지는 모르겠지만 Name>..., 처리되는 데이터에 체계적이고 규칙적으로 나타나는 것이 아니라 항상 존재한다고 가정하겠습니다. ]

간단한 awk 기반 솔루션:

  • 중간 배열은 사용되지 않습니다.
  • 함수 정의에 의존할 필요가 없습니다.
  • 처리 중인 데이터 레코드의 후행 공백 문제를 수정했습니다.
  • awk아래 스크립트에 공백으로 구분된 인수 로 입력 파일을 원하는 수만큼 나열할 수 있습니다 .

주관적으로 말하면 @AdminBee의 답변만큼 우아하지는 않지만 읽기가 더 쉽습니다.

 $ awk -F'>' '($1 == "Name") {
                  if (NR>1) printf "\n"; 
                  gsub(" ","",$2); 
                  printf "%s%s", $2,","}
              ($1 == "Admin") {
                  gsub(" ","",$2); 
                  printf "%s%s", $2,","} 
              ($1 == "Oper") {
                  gsub(" ","",$2); 
                  printf "%s", $2} 
              END {printf "\n"}' input_file
Ami,2,1
Sum,3,
Tar,1,2 
 

위에서 작업은 gsub(" ","",$2)로 표현된 두 번째 필드의 모든 공백을 억제합니다 $2. (OP에는 결과를 표시할 때 혼란을 야기하는 후행 공백이 포함되어 있습니다.)

답변4

입력 데이터가 다음과 유사한 경우(rec 형식):

Name: Ami
Admin: 2
Oper: 1

Name: Sum
Admin: 3
Total: 2

Name: Tar
Admin: 1
Oper: 2

rec2csv | csvcut -C Total... CSV 문서를 생성 하는 데 쉽게 사용할 수 있습니다.

Name,Admin,Oper
Ami,2,1
Sum,3,
Tar,1,2

이는 rec2csv데이터를 CSV로 다시 형식화하는 GNU recutils의 유틸리티이며 csvcutCSV에서 열을 선택하기 위한 유틸리티입니다(여기에서 사용됨).들어오지 못하게 하다Total), csvkit에서.

원시 데이터를 다시 형식화된 형식으로 변환한 awk후 다음을 rec2csv사용하여 공급할 수 있습니다 csvcut.

awk '/^Name>/ { print "" } { sub(">",": "); print }' file | rec2csv | csvcut -C Total

이렇게 하면 으로 시작하는 각 줄 Name>앞에 빈 줄이 오고 각 줄의 첫 번째 항목이 대체됩니다 >.:

tail -n +2CSV 헤더를 제거하려면 결과를 전달하세요.

이는 Name>원본 파일의 각 항목이 새로운 레코드를 도입한다고 분명히 가정합니다.


입력이 다음과 비슷한 경우(xtab 형식):

Name Ami
Admin 2
Oper 1

Name Sum
Admin 3
Total 2

Name Tar
Admin 1
Oper 2

mlr그런 다음 (Miller)를 사용하여 먼저 각 레코드를 "unsparsify"(누락된 키에 null 값 할당)한 다음 CSV 출력 형식으로 필요한 키를 추출할 수 있습니다.

mlr --ixtab unsparsify | mlr --ocsv cut -f Name,Admin,Total

이전 명령과 유사한 명령을 사용하여 원시 데이터를 xtab 형식으로 변환한 awk다음 Miller를 통해 공급할 수 있습니다.

awk '/^Name>/ { print "" } { sub(">"," "); print }' file | mlr --ixtab unsparsify | mlr --ocsv cut -f Name,Admin,Oper

이것이 당신에게 줄 것입니다

Name,Admin,Oper
Ami,2,1
Sum,3,
Tar,1,2

mlr(파이프라인의 마지막) 및 해당 옵션을 사용하여 -NCSV 헤더를 제거합니다.

관련 정보