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,)将变量设置i为从 1 到字段数 ( NF) 的所有值。NR是当前行号,在您的示例中,将为 1 或 2。a[NR][i]=$(i)设置一个二维数组,每行一个数组,并将每个字段保存在其中。基本上,该数组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打印i第一行的列,后跟一个井号,然后是i第二行的列,最后跟一个逗号。它对所有字段执行此操作,保存最后一个字段。

    由于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,可以删掉。

相关内容