【问题标题】:extract each line followed by a line with a different value in column two提取每一行,然后在第二列中提取具有不同值的行
【发布时间】:2016-02-21 20:29:51
【问题描述】:

鉴于以下文件结构,

9.975   1.49000000      0.295   0       0.4880  0.4929  0.5113  0.5245  2.016726        1.0472  -30.7449        1
9.975   1.49000000      0.295   1       0.4870  0.5056  0.5188  0.5045  2.015859        1.0442  -30.7653        1
9.975   1.50000000      0.295   0       0.5145  0.4984  0.4873  0.5019  2.002143        1.0854  -30.3044        2

有没有办法提取第二列中的值不等于下一行第二列中的值的每一行? IE。我想从这三行中提取第二行,因为 1.49 不等于 1.50。 也许使用 sed 或 awk?

这就是我在 MATLAB 中的做法:

myline = 1;
mynewline = 1;
while myline < length(myfile)
    if myfile(myline,2) ~= myfile(myline+1,2)
        mynewfile(mynewline,:) = myfile(myline,:);
        mynewline = mynewline+1;
        myline = myline+1;
    else
        myline = myline+1;
    end
end

但是,我的文件现在太大了,我宁愿在终端中执行此提取操作,然后再将它们传输到我的笔记本电脑。

【问题讨论】:

    标签: bash awk sed extract


    【解决方案1】:

    Awk 应该可以。

    <data awk '($2 != prev) {print line} {line = $0; prev = $2}'
    

    awk 简介:awk 程序由一组condition {code} 块组成。它逐行运行。如果没有给定条件,则为每一行执行该块。 BEGIN 条件在第一行之前执行。每行都拆分为字段,可通过$_number_ 访问。整行在$0

    这里我将第二个字段与上一个值进行比较,如果它不匹配我print整个上一行。在所有情况下,我都将当前行存储到line,将第二个字段存储到prev

    如果你真的想要它,请小心浮点比较 - 类似于abs($2 - prev) &lt; eps(awk 中没有abs,你需要自己定义它,并且 eps 是一个足够小的数字)。我实际上不确定 awk 是否转换为数字以进行相等测试,如果不是,您可以安全地进行字符串比较。

    【讨论】:

    • 不需要第一行 - 从上面的示例中,只有第二行。你能解释一下你的命令的功能吗?我现在正在尝试对其进行测试,但没有任何反应。
    • 你没有指定你的数据在哪里,所以我默认使用标准输入。要实际使用它,您需要将数据放入具有某个名称的文件中,例如 data,然后执行 &lt;data awk ...
    • 啊,明白了——但它会打印上例的第三行。据我了解,这就是发生的情况:我们最初将 -1 作为参考,而不是通过第 2 列并将每个值与参考进行比较。如果值不匹配,则打印当前行并将参考值设置为该行第 2 列的值。现在我只需要弄清楚如何让它打印上一行!
    • 嗯,抱歉误读了问题:) 只需存储整行 ($0) 并有条件地输出。会解决的。
    【解决方案2】:

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

    sed -r 'N;/^((\S+)\s+){2}.*\n\S+\s+\2/!P;D' file
    

    一次读两行。前两列的模式匹配,仅在第二列不匹配时打印第一行。

    【讨论】:

    • 能否请您告诉我如何修改此命令以打印(以防第二列不匹配)不仅是第一行,而且是最后 n 行?
    • @Ango 我不明白你的评论。例子胜于雄辩。
    • cmets 中没有足够的空间作为示例 :) 我想知道如何修改此命令以使其执行以下操作:一次读取两行。前两列的模式匹配,仅在第二列不匹配时打印第一行及其前一行。我想一个人需要一次阅读三行 i.o.这样做。
    【解决方案3】:

    尝试以下命令:

    awk '$2 != field && field { print line } { field = $2; line = $0 }' infile
    

    它保存上一行和第二个字段,在下一个循环中与当前行值进行比较。 &amp;&amp; field 检查有助于避免文件开头出现空行,此时 $2 != field 因为变量为空而匹配。

    它产生:

    9.975   1.49000000      0.295   1       0.4870  0.5056  0.5188  0.5045  2.015859        1.0442  -30.7653        1
    

    【讨论】:

    • 它几乎可以工作了!只有一件事,我想不通:这个命令产生了需要从给定文件中提取的三行中的两行。但是这个命令会遍历文件的所有行,不是吗?...
    猜你喜欢
    • 2016-04-25
    • 1970-01-01
    • 2017-11-15
    • 2019-08-17
    • 1970-01-01
    • 1970-01-01
    • 2015-07-17
    • 1970-01-01
    • 2021-09-29
    相关资源
    最近更新 更多