两个文件中的反向行

时间:2015-05-09 15:46:25

标签: shell sed

我正在尝试反转文件中的行,但我想要两行两行。

对于以下输入:

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

任何帮助将不胜感激。我会试着理解这些公式并自己回答这个问题。

3 个答案:

答案 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.

保持缓冲区始终包含到目前为止处理的输入的反转版本,代码需要两行并将它们粘合到顶部。最后,它被打印出来。

这有两个问题:

  1. 如果输入行数为奇数,则仅打印文件的最后一行,并
  2. 我们在输入结尾处得到一条多余的空行。
  3. 第一个是因为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
    

    另一种方法是将sedtac合并,例如

    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中,然后反向打印出来,两个两个。