我有一个包含20736行的文件。每条81条线代表分子原子的坐标。所以我有256个分子的总坐标。 现在我想为每个单个分子的特定部分选择坐标。例如,在81个细胞系中,我想从每个分子中选择直到第81个直至所有256个分子的第44行。
为了解释很多细节,我想选择行
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中获得解决方案,如果可以用于学习目的。
非常感谢提前。
答案 0 :(得分:3)
m % n
(在许多编程语言中)是“模数”运算符:从n
中删除m
的所有最大可能整数倍之后剩余的余数。
您要打印的行是模数为81的行号至少为43的行。(如果第一行计为第0行,则效果更好;进行调整意味着您需要编号为43-80的行; 124-161; 205-242等(我认为OP有一个小的算术错误,但它可能是一个解释错误。这里的序列是基于stanzas是81行,如OP所说,而不是82行如例子似乎表明)。
所以,在awk中:
awk '(NR-1)%81 >= 43'
这是基于awk的默认操作,即{print}
,所以我没有提供。{/ p>
编辑:如果OP中提供的示例范围是正确的(例如,如果有一个空白行分隔81行节,那么它们可以更改为:
awk 'NR%82>43'
答案 1 :(得分:1)
这是我使用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肯定不是我的强项:\:\似乎工作了!
答案 2 :(得分:1)
已修改 。
使用模数肯定是最好的方法。这个SO问题的最初想法是由@rici添加的!
不幸的是,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
DO
44,81p
126,163p
208,245p
290,327p
...
20544,20581p
20626,20663p
20708,20745p
( Nota:这与SO问题样本完全匹配,但不要以20736结束!!
echo $((20746000/82)) 253000
如果它代表分子,则 20736 系中只有252个完整分子。 )
所以sed
脚本可以写成:
sed -ne '44,81p;126,163p;208,245p;290,327p;...;20626,20663p;20708,20745p' <file
答案 3 :(得分:1)
perl -ne '
BEGIN{ ($f,$t)=(44,81) }
($.==$f .. $.==$t) =~ /(E0|.)$/ or next;
print;
$1 eq "E0" or next;
$_ += 82 for $f,$t;
' file
答案 4 :(得分:1)
使用@ rici的模数概念简单perl:
perl -ne 'print if $.%82>43' file
答案 5 :(得分:1)
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'
答案 6 :(得分:-1)
你的问题陈述很好,但你没有努力。检查head
和tail
命令的组合方式&amp;如何将参数传递给脚本可以帮助您实现所需的目标。
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
答案 7 :(得分:-1)
使用awk
,你可以这样做
awk '
{
if (NR<=t)
{
for (l=t-37;l<=t;l++)
printf "%s ",$l
}
if (NR==t)
{
t+=82
}
} ' t=81 file