我试图弄清楚如何编写一个bash脚本,该脚本使用行之前和之后的行作为条件。我将以类似python的伪代码给出一个例子,这对我来说很有意义。
基本上:
for line in FILE:
if line_minus_1 == line_plus_one:
line = line_minus_1
最好的方法是什么?
所以,如果我有一个输入文件:
3
1
1
1
2
2
1
2
1
1
1
2
2
1
2
我的输出是:
3
1
1
1
2
2
2
2
1
1
1
2
2
2
2
请注意,它从第一行开始直到最后一行,并且尊重先前行中所做的更改,如果我有:
2
1
2
1
2
2
我会得到:
2
2
2
2
2
2
而不是:
2
1
1
1
2
2
答案 0 :(得分:3)
$ awk 'minus2==$0{minus1=$0} NR>1{print minus1} {minus2=minus1; minus1=$0} END{print minus1}' file
3
1
1
1
2
2
2
2
1
1
1
2
2
2
2
minus2==$0{minus1=$0}
如果2行之前的行与当前行相同,则将1行之前的行设置为等于当前行。
NR>1{print minus1}
如果我们超过第一行,则从1行前打印该行。
minus2=minus1; minus1=$0
更新变量。
END{print minus1}
我们读完文件后,打印最后一行。
对于那些喜欢他们的代码分布在多行的人:
awk '
minus2==$0{
minus1=$0
}
NR>1{
print minus1
}
{
minus2=minus1
minus1=$0
}
END{
print minus1
}
' file
答案 1 :(得分:1)
这是一个(GNU)sed解决方案:
$ sed -r '1N;N;/^(.*)\n.*\n\1$/s/^(.*\n).*\n/\1\1/;P;D' infile
3
1
1
1
2
2
2
2
1
1
1
2
2
2
2
这适用于移动的三行窗口。更具可读性:
sed -r ' # -r for extended regular expressions: () instead of \(\)
1N # On first line, append second line to pattern space
N # On all lines, append third line to pattern space
/^(.*)\n.*\n\1$/s/^(.*\n).*\n/\1\1/ # See below
P # Print first line of pattern space
D # Delete first line of pattern space
' infile
N;P;D
是获得移动的两行窗口的惯用方法:追加一行,打印第一行,删除第一行模式空间。为了得到一个移动的三行窗口,我们读取了一行,但只读了一次,即处理第一行(1N
)时。
复杂的位是检查模式空间的第一行和第三行是否相同,如果是,则用第一行替换第二行。要检查我们是否必须进行替换,我们使用地址
/^(.*)\n.*\n\1$/
锚点^
和$
并不是真正需要的,因为我们总是在模式空间中完全具有换行符,但它更清楚地表明我们想要匹配完整的模式空间。我们将第一行放入捕获组,并使用反向引用查看它是否在第三行重复。
然后,如果是这种情况,我们执行替换
s/^(.*\n).*\n/\1\1/
这将捕获第一行(包括换行符),匹配第二行(包括换行符),并替换为第一行的两倍。 P
和D
然后打印并删除第一行。
当到达终点时,整个图案空间被打印,因此我们不会吞下任何线条。
这也适用于第二个输入示例:
$ sed -r '1N;N;/^(.*)\n.*\n\1$/s/^(.*\n).*\n/\1\1/;P;D' infile2
2
2
2
2
2
2
要与BSD sed一起使用(如OS X中所示),您必须使用-E
而不是-r
选项,或者不使用任何选项,即基本常规表达式并转义捕获组中的所有括号(\(\)
)。新行匹配应该有效,但我没有测试它。如果有疑问,请检查this great answer排除所有差异。