【问题标题】:Linux sed join blocks of linesLinux sed 加入行块
【发布时间】:2021-02-13 07:46:57
【问题描述】:

我在 CentOS 下的一个文件中有这些:

real1 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
real2 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
real3 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
173corr 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
512corr 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
513corr 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5

虽然每个块可能包含多个子内容,但有两个块“real”和“corr”,即real1real2 等。

我想加入每个块的子内容。输出将如下所示:

real1 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
173corr 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5

要在Editplus中完成此操作,以真实块为例,我需要突出显示整个真实块,并找到所有出现的\nreal\d+\n并替换为\t\t

挑战是:

  1. 如何在 sed 中突出显示多行。例如,从第 5 行到第 10 行有一个实际块,从 30 到 50 有另一个实际块。每个实际块将突出显示,并在 Editplus 中逐块执行相同的替换。我不知道 sed 是否可以一次完成所有操作。如果不是,指定并在每个块上执行替换即可。

  2. 每个子内容的标题为名称+数字格式,即real1real2等。所以我在 CentOS 上的试用版中添加了\d+,但它似乎不起作用。

我知道这是一个非常复杂的问题。我只是希望 sed 可以解决问题。

【问题讨论】:

  • 名字有关系吗?您需要它并将它们与正确的 bin 相关联,必须有相同数量的子块。否则,它毫无意义。如果关系与计数有关,最好将块的每个名称匹配到单独的数组中,然后根据 index 匹配它们?
  • 你的real\d+\d+corr 行在文件中吗?

标签: regex linux awk sed


【解决方案1】:

我确定 sed 可以 做到这一点,我只是不擅长 sed ... 一个丑陋的 awk 脚本怎么样?

$ cat block
real1 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
real2 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
real3 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
173corr 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
512corr 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
513corr 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5

这里是脚本:

$ cat block.awk
BEGIN{
    block=""
}
{
    newblock=gensub(/[0-9]*([a-z]+)[0-9]*/,"\\1","1",$1)
    if( newblock != block ){
        if(NR>1){print ""}
        for( i=1; i<=NF; i++){
            printf "%s ", $i
        }
    } else {
        for( i=2; i<=NF; i++){
            printf "%s ", $i
        }
    }
    block=newblock
}
END{
    print ""
}

结果:

$ awk -f block.awk block
real1 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 
173corr 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5

【讨论】:

  • 我不介意 sed 或 awk 是否可以工作。 :) 但是我该如何测试您的解决方案。我根本不知道 awk 脚本。我应该把你的代码放在一个 .sh 文件中吗?
  • 不,把它放在任何文件名中,然后像在awk -f block.awk block 中那样调用它...我只是将它命名为 block.awk 以使其与手头的任务相匹配。
  • [root@localhost nn]# awk -f block.awk excel.log real1 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 REAL2 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
  • 行未连接。
  • 我不确定,@WalterA ...我怀疑 Jonathan 的实际文件内容与提供的示例数据不匹配。
【解决方案2】:

这可能对你有用(GNU sed):

sed -E ':a;N;s/^(.*(real|corr).*)\n.*\2\S*/\1/;ta;P;D' file

正常打印行,直到包含realcorr 的行,然后收集以下行,删除换行符和行首信息。在更改键时打印每一行。

【讨论】:

    【解决方案3】:

    real1 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
    real2 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
    real3 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
    173corr 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
    512corr 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
    513corr 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
    

    然后是data.txt

    awk '{current=gensub(/[0-9]/, "", "g", $1);if(current==seen){acc=(acc gensub($1, "", 1))}else{print acc;seen=current;acc=$0}}END{print acc}' data.txt
    

    给出输出:

    real1 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
    173corr 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
    

    说明:我使用两个变量:seen 保留当前类别,其中类别定义为删除所有数字的第一列的内容,acc 加载具有常见类别的行的内容。对于每一行我计算当前类别,如果它与上一行相同,我只将当前行的内容(没有第一行内容)附加到我的acc,否则我打印acc,相应地设置seen并设置@ 987654330@ 到当前的第一行内容。在END 我做print acc,否则最后一个类别的内容会丢失。

    (在 GNU Awk 5.0.1 中测试,API:2.0(GNU MPFR 4.0.2,GNU MP 6.2.0))

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-30
      • 1970-01-01
      • 1970-01-01
      • 2020-02-02
      相关资源
      最近更新 更多