linux - 如何将多列中的数字排序或重新排列为多行[固定为 4 列]?

标签 linux perl awk sed

我有 1 个文本文件,它是 test1.txt。

text1.txt 包含如下内容:
输入:

##[A1] [B1] [T1]  [V1] [T2]  [V2] [T3]  [V3] [T4]  [V4]## --> headers
    1  1000    0   100   10   200   20   300   30   400
              40   500   50   600   60   700   70   800
       1010    0   101   10   201   20   301   30   401
              40   501   50   601  
    2  1000    0   110   15   210   25   310   35   410
              45   510   55   610   65   710
       1010    0   150   10   250   20   350   30   450
              40   550  

条件:
A1 和 B1 -> 每个 A1 + (B1 + [Tn + Vn])
A1 应该在 1 列中。
B1 应该在 1 列中。
T1、T2、T3 和 T4 应在 1 列中。
V1、V2、V3 和 V4 应在 1 列中。

如何将它排序为如下所示?
期望输出:

##   A1    B1   Tn    Vn ## --> headers

      1  1000    0   100
                10   200
                20   300
                30   400
                40   500
                50   600
                60   700
                70   800
         1010    0   101
                10   201
                20   301
                30   401
                40   501
                50   601
      2  1000    0   110
                15   210
                25   310
                35   410
                45   510
                55   610
                65   710
         1010    0   150
                10   250
                20   350
                30   450
                40   550

这是我当前的代码:
第一次尝试:
输入

cat test1.txt | awk ' { a=$1 b=$2 } { for(i=1; i<=5; i=i+1) { t=substr($0,11+i*10,5) v=substr($0,16+i*10,5) if( t ~ /^\ +[0-9]+$/ || t ~ /^[0-9]+$/ || t ~ /^\ +[0-9]+\ +$/ ){ printf "%7s %7d %8d %8d \n",a,b,t,v } }}' | less

输出:

      1    1000      400        0 
     40     500      800        0 
   1010       0      401        0 
      2    1000      410        0 
   1010       0      450        0

我正在尝试使用简单的 awk 命令,但仍然无法得到结果。
谁能帮我解决这个问题?

谢谢,
我是

最佳答案

与其他地方所述的不同,这根本没有什么棘手的,您只是在输入中使用固定宽度的字段而不是字符/字符串分隔的字段。

使用 FIELDWIDTHS 的 GNU awk 来处理固定宽度的字段,这真的再简单不过了:

$ cat tst.awk
BEGIN {
    # define the width of the input and output fields
    FIELDWIDTHS = "2 4 5 5 6 5 6 5 6 5 6 99"
    ofmt = "%2s%5s%6s%5s%6s%s\n"
}
{
    # strip leading/trailing blanks and square brackets from every field
    for (i=1; i<=NF; i++) {
         gsub(/^[[\s]+|[]\s]+$/,"",$i)
    }
}
NR==1 {
    # print the header line
    printf ofmt, $1, $2, $3, "Tn", "Vn", " "$NF
    next
}
{
    # print every other line
    for (i=4; i<NF; i+=2) {
        printf ofmt, $1, $2, $3, $i, $(i+1), ""
        $1 = $2 = $3 = ""
    }
}

.

$ awk -f tst.awk file
##   A1    B1   Tn    Vn ## --> headers
      1  1000    0   100
                10   200
                20   300
                30   400
                40   500
                50   600
                60   700
                70   800
         1010    0   101
                10   201
                20   301
                30   401
                40   501
                50   601
      2  1000    0   110
                15   210
                25   310
                35   410
                45   510
                55   610
                65   710
         1010    0   150
                10   250
                20   350
                30   450
                40   550

对于其他 awk,您将使用 while() { substr() } 循环而不是 FIELDWIDTHS,因此它会多几行代码,但仍然微不足道。

以上将比等效的 shell 脚本快几个数量级。参见 https://unix.stackexchange.com/questions/169716/why-is-using-a-shell-loop-to-process-text-considered-bad-practice .

关于linux - 如何将多列中的数字排序或重新排列为多行[固定为 4 列]?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51146416/

相关文章:

sql - Perl:DBIx::Class 初学者 - 子集关系和预取

bash - 如何使用 awk 追加字段的出现?

linux - 一个进程占用多少核?

perl - 使用 perl 查找系统是小端还是大端

perl - Perl 的模板工具包可以警告未定义的值吗?

regex - 使用 MAWK 时正则表达式与字符串不匹配

unix - 使用 AWK/SED 根据唯一 ID 连接两个变量

linux - 在循环中使用 for 和 sql 输出

linux - Git 打补丁

linux - dos2unix:找到二进制符号,跳过二进制文件