我正在尝试反转文件中的行,但我想要两行两行。
对于以下输入:
FooHack->new
我想要以下输出:
1
2
3
4
…
97
98
我找到了很多方法来逐行反转文件(特别是关于这个主题:How can I reverse the order of lines in a file?)。
97
98
…
3
4
1
2
。最简单的。似乎没有我想要的选项,即使我尝试使用选项tac
和-r
。-s
(不符合POSIX标准)。不符合POSIX标准,我的版本似乎没有任何关系。仍然是三个sed公式,我认为稍作修改就可以了。但我甚至不理解他们在做什么,因此我被困在这里。
tail -r
任何帮助将不胜感激。我会试着理解这些公式并自己回答这个问题。
答案 0 :(得分:2)
好的,我会咬人的。在纯sed中,我们必须在打印之前在保持缓冲区中构建完整的输出(因为我们看到最后要打印的东西)。基本模板可能如下所示:
sed 'N;G;h;$!d' filename # Incomplete!
那是:
N # fetch another line, append it to the one we already have in the pattern
# space
G # append the hold buffer to the pattern space.
h # save the result of that to the hold buffer
$!d # and unless the end of the input was reached, start over with the next
# line.
保持缓冲区始终包含到目前为止处理的输入的反转版本,代码需要两行并将它们粘合到顶部。最后,它被打印出来。
这有两个问题:
第一个是因为N
在输出中不存在更多行时会失效,这会出现奇数个输入行;我们可以通过仅在输入结束尚未到达时有条件地执行它来解决问题。与上面的$!d
一样,这是通过$!N
完成的,其中$
是输入结束条件,!
将其反转。
第二个是因为在最开始时,保持缓冲区包含一个空行,G
在第一次运行代码时附加到模式空间。由于$!N
我们不知道在那一点行计数器是1还是2,我们应该在两者上有条件地禁止它。这可以使用1,2!G
来完成,其中1,2
是从第1行到第2行的范围,因此如果行计数器不在1之间,1,2!G
将运行G
和2.
然后整个脚本变为
sed '$!N;1,2!G;h;$!d' filename
另一种方法是将sed
与tac
合并,例如
tac filename | sed -r 'N; s/(.*)\n(.*)/\2\n\1/' # requires GNU sed
这不是在这里使用sed
的最短方式(您也可以使用tac filename | sed -n 'h;$!{n;G;};p'
),但也许更容易理解:每次处理新行时,N
都会抓取另一行,s
命令交换它们。因为tac
反向输入行,所以这会将线对恢复为原始顺序。
与第一种方法的关键区别在于奇数行的行为:对于第二种方法,文件的第一行将是没有伙伴的单独行,而第一行则是最后一行。< / p>
答案 1 :(得分:1)
我会这样做:
tac file | while read a && read b; do echo $b; echo $a; done
答案 2 :(得分:0)
以下是您可以使用的awk
:
cat file
1
2
3
4
5
6
7
8
awk '{a[NR]=$0} END {for (i=NR;i>=1;i-=2) print a[i-1]"\n"a[i]}' file
7
8
5
6
3
4
1
2
它将所有行存储在数组a
中,然后反向打印出来,两个两个。