【问题标题】:Split column into multiple based on match/delimiter using bash awk使用 bash awk 根据匹配/分隔符将列拆分为多个
【发布时间】:2018-05-14 13:29:03
【问题描述】:

我在单个列中有一个数据集,当找到某个字符串时,我想将其拆分为任意数量的新列(在本例中为“male_position”。

>cat test.file

male_position
0.00
0.00
1.05
1.05
1.05
1.05
3.1
5.11
12.74
30.33
40.37
40.37
male_position
0.00
1.05 
2.2
4.0
4.0
8.2
25.2
30.1
male_position
1.0
5.0

我希望脚本在每次遇到“male_position”时生成新的制表符分隔列,但只打印其下方的每一行/数据点(添加到该列),直到下一次出现“male_position”:

script.awk test.file > output

0.00  0.00  1.0
0.00  1.05  5.0
1.05  2.2
1.05  4.0
1.05  4.0
1.05  8.2
3.1  25.2
5.11 30.1
12.74
30.33
40.37
40.37

有什么想法吗?

更新 - 我试图根据这篇文章改编代码(Linux split a column into two different columns in a same CSV file

cat script.awk

BEGIN {
   line = 0; #Initialize at zero
}
/male_position/ { #every time we hit the delimiter
   line = 0; #resed line to zero
}
!/male_position/{ #otherwise
   a[line] = a[line]" "$0; # Add the new input line to the output line
   line++; # increase the counter by one
}
END {
   for (i in a )
      print a[i] # print the output
}

结果....

$ awk -f script.awk test.file
 1.05 2.2
 1.05 4.0
 1.05 4.0
 1.05 8.2
 3.1 25.2
 5.11 30.1
 12.74
 30.33
 40.37
 40.37
 0.00 0.00 1.0
 0.00 1.05  5.0

更新 2 #######

我可以使用 test.file 案例重新创建预期。在 Linux 上使用测试文件和“awk.script”(见上文)运行脚本(script.awk)似乎可以工作。但是,这个简单的示例文件在分隔符(male_position)之间的列(数据点)数量只减少了。当您增加之间的列数时,输出似乎失败...

cat test.file2

male_position
0.00
0.00
1.05
1.05
1.05
1.05
3.1
5.11
12.74
male_position
0
5
10
male_position
0
1
2
3
5

awk -f script.awk test.file2

0.00 0 0
0.00 5 1
1.05 10 2
1.05 3
1.05 5
1.05 
3.1
5.11
12.74

在给定列的最后一次观察之后没有“填充”行,因此值多于前一列的列的值与前一列一致(3 和 5 在第 2 列,当它们应该在第 3 列时)。

【问题讨论】:

  • 我已尝试调整上一篇文章中的一些代码:stackoverflow.com/questions/14709360/…,但无法根据使用的分隔符 (male_position) 将预期输出恢复到不同的列中。
  • this code 中将,, 替换为male_position?
  • 是的,我已经尝试过了,但它并不完全有效...... 'male_position' 之后的前 2 行放在列的末尾,而不是我期望的开头.
  • 或试试accepted answer
  • 再次,我已经尝试从“接受的答案”中调整代码,但没有得到预期的结果。相反,在分隔符匹配到“组”末尾之后,我们得到了前两行的一些有趣行为——也许带有“0.0”的行正在将其丢弃(带有 1.0 和 5.0 的第三个“组”似乎工作正常很好,但前两个没有...

标签: bash awk


【解决方案1】:

这是csplit+paste 解决方案

$ csplit --suppress-matched -zs test.file2 /male_position/ {*}
$ ls
test.file2  xx00  xx01  xx02
$ paste xx*
0.00    0   0
0.00    5   1
1.05    10  2
1.05        3
1.05        5
1.05        
3.1     
5.11        
12.74       

来自man csplit

csplit - 将文件拆分为由上下文行确定的部分

-z, --elide-empty-files 删除空输出文件

-s, --quiet, --silent 不打印输出文件大小的计数

--抑制匹配 抑制匹配 PATTERN 的行

  • /male_position/ 是用于分割输入文件的正则表达式
  • {*} 指定创建尽可能多的拆分
  • 使用-f-n 选项更改默认输出文件名
  • paste xx* 按列粘贴文件,TAB 是默认分隔符

【讨论】:

    【解决方案2】:

    关注awk 可能对您有所帮助。

    awk '/male_position/{count++;max=val>max?val:max;val=1;next} {array[val++,count]=$0} END{for(i=1;i<=max;i++){for(j=1;j<=count;j++){printf("%s%s",array[i,j],j==count?ORS:OFS)}}}' OFS="\t"   Input_file
    

    现在也添加非单线形式的解决方案。

    awk '
    /male_position/{
      count++;
      max=val>max?val:max;
      val=1;
      next}
    {
      array[val++,count]=$0
    }
    END{
      for(i=1;i<=max;i++){
          for(j=1;j<=count;j++){   printf("%s%s",array[i,j],j==count?ORS:OFS)   }}
    }
    ' OFS="\t"   Input_file
    

    【讨论】:

      猜你喜欢
      • 2016-08-01
      • 1970-01-01
      • 2018-02-19
      • 1970-01-01
      • 1970-01-01
      • 2013-10-19
      • 1970-01-01
      • 2013-06-07
      • 1970-01-01
      相关资源
      最近更新 更多