Bash: 여러 줄 출력을 한 줄로 변환

Bash: 여러 줄 출력을 한 줄로 변환

내가 얻는 여러 줄 출력은 다음과 같습니다.

실제 출력:

GenuineIntel,Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz,CPU0,64,EM64T Family 6 Model 45 Stepping 7,(null),3093,0
GenuineIntel,Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz,CPU1,64,EM64T Family 6 Model 45 Stepping 7,(null),3093,0

#Bash 스크립트에서는 위 출력을 기호로 구분된 한 열과 쉼표로 구분된 두 열의 값이 있는 행으로 변환해야 합니다 .

예상 출력:

GenuineIntel#GenuineIntel,Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz#Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz,CPU0#CPU1 and so on.

어떻게 하나요?

답변1

awk다음은 파일의 특정 내용에 의존하지 않는 보다 일반적인 접근 방식입니다 .

awk -F, '{for(i=1;i<=NF;i++){a[NR][i]=$(i)}}
         END{
            for(i=1;i<NF;i++){printf "%s#%s,",a[1][i],a[2][i]} 
            print a[1][NF]"#"a[2][NF]
        }' file

설명하다

  • for(i=1;i<=NF;i++){a[NR][i]=$(i)}: 각 행의 필드( 로 구분됨 -F,)를 반복하여 변수를 i1부터 필드 수( )까지의 NF모든 값 으로 설정합니다. NR현재 줄 번호입니다. 귀하의 예에서는 1 또는 2입니다. a[NR][i]=$(i)행당 하나씩 2D 배열을 설정하고 여기에 각 필드를 저장합니다. 기본적으로 배열은 a다음과 같습니다.

      1                        2                        3   
    1 1st field of 1st line    2nd field of 1st line    3rd field of 1st line
    2 1st field of 2nd line    2nd field of 2nd line    3rd field of 2nd line
    

    등. 그러면 이것이 a[1][2]첫 번째 행의 두 번째 필드가 됩니다.

  • END{}: 파일의 나머지 부분을 처리한 후 이 작업을 실행합니다.

  • for(i=1;i<NF;i++){printf "%s#%s,",a[1][i],a[2][i]}: 모든 필드를 반복하고 첫 번째 행의 현재 필드 #와 두 번째 행의 해당 필드를 인쇄합니다.
  • print a[1][NF]"#"a[2][NF]:마지막 필드를 인쇄합니다(한 줄씩). 이것은 별도로 수행되므로 다른 것을 인쇄하고 그 뒤에 쉼표를 붙일 수 있지만 이 것 뒤에는 개행 문자가 옵니다.

Perl에서도 동일한 아이디어가 작동합니다.

perl -F, -ane 'chomp($F[$#F]);
               $k{$.}=\@F; 
               END{
                for($l=0;$l<$#F;$l++){
                  print "${$k{1}}[$l]#${$k{2}}[$l],"
                }
                print "${$k{1}}[$#F]#${$k{2}}[$#F]\n"}' file

이는 파일에 있는 특정 텍스트에 의존하지 않는다는 장점이 있습니다. 각 행에 동일한 수의 쉼표로 구분된 필드가 있는 한 모든 데이터 행에 대해 작동합니다.

답변2

perl골프:

perl -F, -lane'push@{$f[$_]},$F[$_]for 0..$#F}{$,=",";$"="#";print map"@{$_}",@f'

답변3

입력 데이터가 다음 이름의 파일에 있는 경우 input:

$ awk -F, '/CPU0/{for (i=1; i<=NF;i++) {a[i]=$i};next} {for(i=1;i<=NF-1;i++){printf a[i]"#"$i","}; print a[NF]"#"$NF}' input
GenuineIntel#GenuineIntel,Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz#Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz,CPU0#CPU1,64#64,EM64T Family 6 Model 45 Stepping 7#EM64T Family 6 Model 45 Stepping 7,(null)#(null),3093#3093,0#0

awk한 번에 하나의 명령을 실행합니다.

  • -F,

    이는 awk입력 필드 구분 기호로 쉼표를 사용하라는 의미입니다.

  • /CPU0/{for (i=1; i<=NF;i++) {a[i]=$i};next}

    첫 번째 /CPU0/는 첫 번째 행(CPU0에 대한 행)을 선택하는 주소 선택기입니다. 이 행의 경우 모든 필드 값을 배열에 저장합니다 a. 이 명령은 다음 줄로 점프하라고 next알려줍니다 .awk

  • for(i=1;i<=NF-1;i++){printf a[i]"#"$i","}

    이는 첫 번째 행의 열, 해시 기호, 두 번째 행의 열, 쉼표를 차례로 awk인쇄하라는 의미입니다. 모든 필드에 대해 이 작업을 수행하고 마지막 필드를 저장합니다.ii

    printf사용되므로 개행 문자는 인쇄되지 않습니다 .

  • print a[NF]"#"$NF}

    이는 awk첫 번째 줄의 마지막 필드를 인쇄하고 그 뒤에 파운드 표시를 지정한 다음 두 번째 줄의 마지막 필드를 인쇄하도록 지시합니다.

    사용되기 때문에 print마지막 문자는 개행 문자로 인쇄되어 출력이 완료됩니다.

답변4

$ cat /tmp/tmp     
GenuineIntel,Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz,CPU0,64,EM64T Family 6 Model 45 Stepping 7,(null),3093,0     
GenuineIntel,Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz,CPU1,64,EM64T Family 6 Model 45 Stepping 7,(null),3093,0     
GenuineIntel,Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz,CPU2,64,EM64T Family 6 Model 45 Stepping 7,(null),3093,0    
$ awk -F ',' 'BEGIN{ORS=" ";cpu=",";print "GenuineIntel,"} {gsub(/GenuineIntel/,"");for (i=1;i<=2;i++) {printf $i};print "#";cpu=cpu"#"$3 } END{sub(/,#/,",",cpu);print cpu}' /tmp/tmp
GenuineIntel,  Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz #  Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz #  Intel(R) Xeon(R) CPU E5-2687W 0 @ 3.10GHz # ,CPU0#CPU1#CPU2     

완벽하지는 않습니다. #끝에 한 줄이 더 있습니다. 앞쪽에 있으므로 ,CPU0#CPU1#CPU2삭제할 수 있습니다.

관련 정보