【问题标题】:How can I remove specific lines block wise using linux commands?如何使用 linux 命令逐块删除特定行?
【发布时间】:2014-10-24 02:56:48
【问题描述】:

我有以下数据文件,由重复的数据块组成。

 486  Examples                    Iteration:  300000 #Bonds:  10
    1    6    3    5    7  371    0    0    0    0    0    0    1  0.935  0.932  0.955  0.852  0.000  0.000  0.000  0.000  0.000  0.000  3.736  0.000  1.303
    2    6    4  143  386  389    0    0    0    0    0    0    1  0.892  0.877  0.855  0.918  0.000  0.000  0.000  0.000  0.000  0.000  3.751  0.000  0.999
    3    3    1   18    0    0    0    0    0    0    0    0    1  0.935  0.901  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  1.926  2.000 -0.708
    4    3    2   18    0    0    0    0    0    0    0    0    1  0.892  0.923  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  1.829  2.000 -0.756
...
  482    3   16  483    0    0    0    0    0    0    0    0    1  0.954  0.831  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  1.809  2.000 -0.716
  483    2  482    0    0    0    0    0    0    0    0    0    1  0.831  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.884  0.000  0.457
  484    2  485    0    0    0    0    0    0    0    0    0  105  0.865  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.936  0.000  0.372
  485    3  213  484    0    0    0    0    0    0    0    0  105  0.835  0.865  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  1.779  2.000 -0.665
  486    2  440    0    0    0    0    0    0    0    0    0   44  0.829  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.896  0.000  0.345
   634.597636118845        347.992894465888        1330.58342505062
 -1.280885974547230E-005
 486  Examples                    Iteration:  300001 #Bonds:  10
    1    6    3    5    7  371    0    0    0    0    0    0    1  0.935  0.932  0.955  0.852  0.000  0.000  0.000  0.000  0.000  0.000  3.736  0.000  1.303
    2    6    4  143  386  389    0    0    0    0    0    0    1  0.892  0.877  0.855 
...

同样,我的数据文件由很多数据块组成,每个数据块总共有 489 行。但是真正的数据行只有486行,而且有1个header line和2个tailing line。

在这里,我希望为所有数据块删除1个标题行和2个尾行,(删除所有数据的每(1 * n,488 * n和489 * n)行。n =数据块的数量) 并删除所有浮动列(仅读取到第 13 列)。所以,我希望得到像

这样的文件
    1    6    3    5    7  371    0    0    0    0    0    0    1  
    2    6    4  143  386  389    0    0    0    0    0    0    1  
    3    3    1   18    0    0    0    0    0    0    0    0    1
    ...
    484    2  485    0    0    0    0    0    0    0    0    0  105
    485    3  213  484    0    0    0    0    0    0    0    0  105
    486    2  440    0    0    0    0    0    0    0    0    0   44
    1    6    3    5    7  371    0    0    0    0    0    0    1  
    2    6    4  143  386  389    0    0    0    0    0    0    1 
    ...

这种格式。如何删除每个数据块的 1 个标题行 + 2 个尾行?我想我可以通过 awk print 命令读取前 13 列。但我不知道如何从数据中删除那些额外的行。是否有使用 awk + ​​NR 组合或其他 linux 命令的简单方法?

谢谢

【问题讨论】:

  • 页眉和尾行是否有唯一可识别的信息?字段的数量对此有用吗?
  • @EtanReisner 一些页眉和尾行在未来的分析中很有用,但我有 fortran 90 代码可以做到这一点。目前,我只对删除标题和尾行感兴趣,并删除 14~last 列。
  • 你试过什么?我很乐意帮助您编写 awk 脚本,但您需要发布代码以便我们帮助您改进它。
  • 说您只想保留具有 16 个字段的行是否有效?如果是这样,那么awk 'NF == 16 { $14=""; $15=""; $16=""; print}' file.dat 可能就足够了......

标签: linux bash awk


【解决方案1】:

您可以通过使用模数过滤掉每个块中的非数据行以仅打印特定行。然后,您可以使用 for 循环仅打印前 13 列。

awk 'NR  % 489 != 0 && NR % 489 != 1 && NR % 489 != 488 {for (i = 1; i < 13; i++) printf "%s\t",$i; print ""}' Input.txt

一些解释:

NR 是行号,从 1 开始。&amp;&amp; 是逻辑 AND。我们正在打印编号 mod 489 与 1、488 和 489 不匹配的所有行。

【讨论】:

  • 谢谢,这行得通,但整个列在第 13 列之后重复。我怎样才能摆脱呢?
  • 另外,你能解释一下 NR 和 && 命令在这里是如何工作的吗?
  • @exsonic01 我假设您的意思是整行重复。我做了一个应该解决这个问题的编辑。
  • 谢谢。请检查我对您的代码的理解是否正确。 'NR % 489' 表示所有重复的 489 行,'!=0' 表示读取除了最后一个尾行,'!=1' 表示读取除了 last-1 尾行,'!=488' 表示标题行。是这样吗?
  • @exsonic01,!=1 指标题行,!=0 指 489,!=488 指倒数第二行。
【解决方案2】:

假设样本行真正代表数据,那么这样的事情可能会奏效。

awk 'NF <= 8 {next} NF=13' datafile

这将丢失列格式。假设每一行在每一列中都有一个值,您可以通过将输出传递到 column -t 来重构列格式,尽管这与输入不同。

该 sn-p 中的 8 是一个任意数字,大于给定的任何示例行上的字段数且小于 13

【讨论】:

  • 谢谢。格式在这里并不重要,但我更喜欢 %7d。我可以使用 awk printf 再次以格式制作列。顺便说一句,你能解释一下 awk 命令吗?另外如何删除 1 个标题和 2 个尾行?
  • 您当然可以手动格式化输出,而不是让 awk 默认在那里打印它。只需使用{for (i=1; i&lt;=13; i++) {printf "%7d%s", $i, OFS}} 或类似的东西。
  • 该脚本将这些行放在第一个 {next} 块中,因为它们的字段少于 8。 (八是大于给出的示例行且小于 13 的任意数字。)
  • 感谢您的解释。
猜你喜欢
  • 2021-05-02
  • 1970-01-01
  • 2018-05-23
  • 1970-01-01
  • 1970-01-01
  • 2019-01-11
  • 2019-08-04
  • 2018-03-12
  • 1970-01-01
相关资源
最近更新 更多