【问题标题】:selecting specific lines repetitively from a file从文件中重复选择特定行
【发布时间】:2013-10-05 14:52:47
【问题描述】:

我有一个包含 20736 行的文件。每 81 行代表分子原子的坐标。所以我有 256 个分子的总坐标。 现在我想为每个分子的特定部分选择坐标。例如,在 81 行中,我只想从每个分子中选择第 44 行到第 81 行,直到所有 256 个分子。

为了解释更多细节,我想选择行

44-81 from 1-81 lines
126-163 from 82-163 lines
208-245 from 164-245 lines
290-327 from 246-327 lines
and so on until 20736 lines

为了实现这一点,我尝试了如下 bash 脚本:

#!/bin/bash           

while read line           
do           
echo "$line"           

done < malto-thermo-RT.set30.traj.pdbL1 

但我不确定如何继续执行循环以从文件的每 81 行中仅选择第 44 行到第 81 行。

感谢我得到一些帮助。

如果可以的话,我也希望在 python、awk 和 perl 中获得解决方案以用于学习目的。

非常感谢。

【问题讨论】:

  • 开始写Python吧,我们不是为你做的。
  • @sudo_O: 好的,我明白怎么了:第一个必须从0 开始,因为163-82=81245-164=81 也是81-0=81,而不是81-1!!!跨度>
  • @vijay:您的示例行范围与您的问题不一致。如果您继续示例直到第 256 个分子,您将拥有 20954-20991 的范围,但您声称文件中只有 20736 行。
  • 亲爱的@rici,你是对的。我错过了文件中每 81 行一次的行分隔符。对此深表歉意。
  • @Vijay:请更正您的帖子:不可能有20736256 分子和81 + 1 行+ sep。

标签: python perl bash awk


【解决方案1】:

m % n(在许多编程语言中)是“模”运算符:在从m 中删除所有可能的最大整数倍 n 之后剩下的余数。

您要打印的行是行号模 81 至少为 43 的行。(如果将第一行计为第 0 行,这会更好;进行调整意味着您希望行编号为 43-80 ; 124-161; 205-242 等(我认为 OP 有一个小的算术错误,但这可能是一个解释错误。这里的顺序是基于 81 行的节,正如 OP 所说,而不是 82 行正如这个例子似乎表明的那样)。

所以,在 awk 中:

awk  '(NR-1)%81 >= 43' 

这是基于 awk 的默认操作,即 {print},所以我不必提供。

编辑:如果 OP 中提供的示例范围是正确的(例如,如果有一个空行分隔 81 行小节,它们就是正确的,那么可以将其更改为:

awk 'NR%82>43'

【讨论】:

  • 我不认为这是 OP 算术错误。看我的回答stackoverflow.com/a/19178113/1066031
  • @rici Care:SO 问题是错误的:第一步必须从0 开始,而不是1
  • @F.Hauri:如果这是真的,每个分子会有 82 行;问题是 81。此外,问题是 256 个分子有 20736 行,正好是 81 行/分子。这消除了存在与示例范围一致的分隔线的可能性。所以要么问题不正确,要么示例行范围不正确。我的解决方案适用于该问题,而不是示例行范围。无论如何,只要给出一个一致的问题,就很容易解决。
  • @rici 是的,您对歧义是正确的。我的假设是较低的范围更可能是正确的。这也是公认答案的作用。但是,对于 OP 的澄清会很好
  • @sudo_O:是的。无论如何,两者都很容易。我添加了另一个。
【解决方案2】:
perl -ne '
  BEGIN{ ($f,$t)=(44,81) }
  ($.==$f .. $.==$t) =~ /(E0|.)$/ or next;
  print;
  $1 eq "E0" or next;
  $_ += 82 for $f,$t;
' file

【讨论】:

  • 非常感谢:我已阅读 man perlop 以了解您的帖子(或 man -P'less +/\\.\\..*==' perlop)。但是我今天学到了一些东西! ...无论如何使用模数,这可以写得更简单:perl -ne 'print if (($.%82)==44..($.%82)==81)'
  • @F.Hauri 你是对的模数。至于..,它是一个范围运算符。 perldoc.perl.org/perlop.html#Range-Operators
【解决方案3】:

这是我使用 bash 的天真、非惯用的破解它:

#!/bin/bash
file=/tmp/file
segment_size=81
select_offset=44
select_size=37

start_line=$select_offset
end_line=$(($start_line + $select_size))

i=0
while read line
do
    i=$(($i + 1))
    if [ $i -ge $start_line ]; then

        [ $i -eq $start_line ] && [ $i != 1 ] && echo -e "\n-------------------\n"

        if [ $i -le $end_line ]; then
            echo "$line"

            if [ $i -eq $end_line ]; then
                start_line=$(($start_line + $segment_size + 1))
                end_line=$(($start_line + $select_size))
            fi
        fi
    fi
done < $file

Bash 肯定不是我的强项 :\ :\ 似乎也可以!

【讨论】:

    【解决方案4】:

    rici 使用模数运算符的想法是正确的,但随着记录的增加,他的解决方案逐渐变得不同步,如下所示:

    $ seq 350 | awk  '(NR-1)%81==43{printf "%i",$0} (NR-1)%81==80{print " -",$0}' 
    44 - 81                         # In sync
    125 - 162                       # Out of sync by 1 
    206 - 243                       # Out of sync by 2 
    287 - 324                       # Out of sync by 3 
    

    要打印您要求的行,您可以:

    $ awk 'NR%82>43' file
    

    打印的范围是:

    $ seq 350 | awk  'NR%82==44{printf "%i",$0} NR%82==81{print " -",$0}'
    44 - 81
    126 - 163
    208 - 245
    290 - 327
    

    测试自己:

    $ seq 350 | awk  'NR%82>43'
    

    【讨论】:

    • 好的,我明白了问题所在:第一个必须从0 开始,因为163-82=81245-164=81 也是81-0=81,而不是81-1!!!
    • @sudo_O:在我的解决方案中查看我对 F.Hauri 的回复。很烦你不能对两个人发表评论。
    【解决方案5】:

    使用@rici 的模数思想的简单 perl:

    perl -ne 'print if $.%82>43' file
    

    【讨论】:

      【解决方案6】:

      已编辑由于 SO 问题的错误。

      使用模数无疑是最好的方法。 @rici 添加了这个 SO question 中的原始想法!

      不幸的是,SO 问题是错误的:...从 82-163 行(包括),而不是 ...从 164-245 行,我数 82 行,而不是 81。

      首先,我只想提供我的 + 替代解决方案。

      但现在更正了,为了更好地匹配 SO 问题,这可能有助于显示错误在哪里:

      sed -nf <(for ((i=0;i<20736;i+=82));do echo $((i+44)),$(($i+81))p;done ) < file
      

      bash 生成 sed 命令并由 sed 完成工作。

      拆分解释

      bash 部分:

      for ((i=0;i<20736;i+=82)) ;do
          echo $((i+44)),$(($i+81))p
        done
      

      44,81p
      126,163p
      208,245p
      290,327p
      ...
      20544,20581p
      20626,20663p
      20708,20745p
      

      ( 注意: 这与 SO 问题样本完全匹配,但不要以 20736 结尾!!

         echo $((20746000/82))
         253000
      

      如果它代表分子,则只有 252 个完整的分子,在 20736 行中。 )

      所以sed 脚本可以写成:

      sed -ne '44,81p;126,163p;208,245p;290,327p;...;20626,20663p;20708,20745p' <file
      

      【讨论】:

        【解决方案7】:

        使用awk,你可以这样做

        awk '
            {
            if (NR<=t) 
                {
                for (l=t-37;l<=t;l++) 
                    printf "%s ",$l
                }
            if (NR==t)
                {
                t+=82
                }
            } ' t=81 file
        

        【讨论】:

        • 感谢您的帮助。但是当我运行时,我没有任何输出。屏幕似乎只有在完成运行之前是空白的。
        • 现在可以试试吗?当我们没有文件时,这有些困难。
        • @jotne 除了是错误的方法之外,您的答案还有很多错误。如果您希望输入文件使用seq 进行测试以生成整数列表。
        • 我确实有一个 a 额外的,用于测试,已删除。逻辑没问题。行1 给出字段44-81,行2 字段44-81 等到行81,然后行82 to 163 打印字段126 to 163
        • OP 没有要求拆分字段,他只想要打印第 44-81、126,163 行等。
        【解决方案8】:

        你的问题陈述很好,但你没有努力。检查 headtail 命令的组合以及如何将参数传递给脚本可以帮助您实现所需的目标。

        http://www.ss64.com/bash/head.html
        http://www.ss64.com/bash/tail.html

        例如,

        $ cat file
        line1
        line2
        line3
        line4
        line5
        line6
        line7
        line8
        line9
        line10
        

        在本例中,我们可以使用以下命令打印第 3 到第 7 行:

        $ head -7 file | tail -5
        line3
        line4
        line5
        line6
        line7
        

        【讨论】:

        • 如果有人投反对票,我认为他/她也应该抽出一些时间让我知道为什么这样做,以便我可以改进。
        • 这可能被否决了,因为您的解决方案是查看head 命令。你能建议head 命令在这里有什么帮助吗?
        • @sudo_O:感谢您指出我的错误。我应该提到“head”和“tail”命令的组合;我只提到了一个。我会改正的。
        • 你将如何在一个文件中打印多个范围?
        • 如果我们已经有了范围,我们不能将它们作为参数传递并以两个为一组(最小和最大)处理它们吗?我猜将需要更多的行来实现。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-27
        • 2011-10-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-07
        相关资源
        最近更新 更多