我在上一篇文章中使用awk解决了一个问题,但现在我想在其中放入一个if循环,但我遇到了一个错误。
问题是:
我有很多文件看起来像这样:
Header
175566717.000
175570730.000
175590376.000
175591966.000
175608932.000
175612924.000
175614836.000
.
.
.
175680016.000
175689679.000
175695803.000
175696330.000
我想提取前2000行(第1行到2000行),然后提取第1500行到3500行,然后提取3000行到5000行,以此类推……我的意思是:提取一个2000行的窗口,在相邻窗口之间重叠500行,直到文件结束。
这是用于它的awk命令:
awk -v i=1 -v t=2000 -v d=501 'NR>1{a[NR-1]=$0}END{
while(i<NR-1){
++n;
for(k=i;k<i+t;k++)print a[k] > "win"n".txt";
close("_win"n".txt")
i=i+t-d
}
}' myfile.txt
done
我得到了几个名为win1.txt、win2.txt、win3.txt等的文件…
我现在的问题是,因为文件不是2000的倍数,所以我上一个窗口的行数不到2000。我该如何放置一个if循环来实现这一点:如果最后一个窗口的数字少于2000,那么前一个窗口应该有所有的行,直到文件结束。
额外信息
创建窗口时,在末端会有一个换行符。这就是为什么我需要if循环来考虑少于2000个数字的窗口,而不仅仅是行。
如果由于其他原因不必使用awk,请尝试sed方法
#!/bin/bash
file="$(sed '/^s*$/d' myfile.txt)"
sed -n 1,2000p <<< "$file"
first=1500
last=3500
max=$(wc -l <<< "$file" | awk '{print $1}')
while [[ $max -ge 2000 && $last -lt $((max+1500)) ]]; do
sed -n "$first","$last"p <<< "$file"
((first+=1500))
((last+=1500))
done
显然,这将比awk更快,而且对于千兆文件来说更容易出错,但在大多数情况下都应该有效。
更改while
条件使其提前停止:
while (i+t <= NR) {
更改for
循环的结束条件,以补偿可能更大的最后一个输出文件:
for (k = i; k < (i+t+t-d <= NR ? i+t : NR); k++)
代码的其余部分可以保持不变;尽管我随意删除了close
语句(为什么这样?),并设置了d=500
,以使输出文件真正重叠500行。
awk -v i=1 -v t=2000 -v d=500 'NR>1{a[NR-1]=$0}END{
while (i+t <= NR) {
++n;
for (k=i; k < (i+t+t-d <= NR ? i+t : NR); k++) print a[k] > "win"n".txt";
i=i+t-d
}
}' myfile.txt
我用t
和d
的小值对它进行了测试,它似乎按要求工作。
最后一句话:对于大的输入文件,我不鼓励将整个内容存储在数组a
中。