如何反转文本文件的行?

31

我正在编写一个小型的shell脚本,需要反转文本文件中的行。是否有标准的过滤命令可以做到这样的事情?

我的具体应用是,我正在获取Git提交标识符的列表,并且我想以相反的顺序处理它们:

git log --pretty=oneline work...master | grep -v DEBUG: | cut -d' ' -f1 | reverse

我想到的最好的方法是像这样实现 reverse

... | cat -b | sort -rn | cut -f2-

这个命令使用cat对每一行进行编号,然后使用sort以数字降序排序(导致整个文件倒过来),最后使用cut删除不需要的行号。

以上方法适用于我的应用程序,但在普遍情况下可能会失败,因为 cat -b 只对非空行进行编号。

有更好、更通用的方法吗?


可能是重复的问题:如何反转文件中行的顺序? - tripleee
不是针对文本文件中行的反转,而是特别针对您的情况,您可以按时间顺序打印提交记录:git log --reverse - 13k
9个回答

57

使用示例http://www.thegeekstuff.com/2009/10/file-manipulation-examples-using-tac-rev-paste-and-join-unix-commands/ - Fedir RYKHTIK
它也可以在MacOS上使用,但是需要使用brew先安装coreutils,然后再使用gtac命令。 - Cyberwiz
哦天啊,那真是让我笑得好厉害。 - gpoussif

32

有一个适合您目的的命令:

tail -r file.txt
  • 以相反的顺序打印file.txt文件的行!
  • -r 标志不标准,可能不适用于所有系统,例如在macOS上有效。
  • 注意:行数受限。大多数情况下有效,但处理大型文件时要小心并进行检查。

7
POSIX规范中的tail命令没有提到“-r”选项。 - Richard Hansen
3
在OS X 10.7的手册中,人们可以看到:“tail实用程序预期是IEEE Std 1003.2-1992(“POSIX.2”)规范的超集。特别是,-F、-b和-r选项是该标准的扩展。” - Wes
2
我认为-r选项在类似FreeBSD的BSD变体中也是可用的,但不适用于gnu tail。 - mc0e
1
仅供参考,行数有限,因此无法处理大文件/流,但在处理小型和中型文件时非常有用。因此,如果您正在处理特定大小的文件,请进行测试。 - NeronLeVelu
1
这不是标准,你应该说明它适用于哪些系统,或者至少不要说它是标准的。 - zezollo
显示剩余4条评论

24

答案不是42,而是tac

编辑:使用sed速度较慢但更消耗内存。

sed 'x;1!H;$!d;x'

甚至更长

perl -e'print reverse<>'

神秘,但这正是我在寻找的。谢谢! - Greg Hewgill
2
'tac'并不神秘:它是'cat'倒过来。;-) - Charlie Martin
1
没错,但如果没有事先知道的话,我肯定猜不到。你可以把排序程序叫做“abc”,这样也有意义,但不会帮助别人猜出它的名字! - Greg Hewgill
1
在msysgit中,我没有tac命令,但我有sed命令。谢谢! - Daniel Yankowsky

3
与上述使用 sed 的示例类似,使用 perl - 可能更加记忆犹新(取决于您的大脑如何编程):
perl -e 'print reverse <>'

2
在这种情况下,只需使用--reverse
$ git log --reverse --pretty=oneline work...master | grep -v DEBUG: | cut -d' ' -f1

2
"cat -b"只会给非空行编号,如果您只想避免这个问题,为什么不使用"cat -n"来对所有行进行编号呢?

好的观点,我想我没有仔细阅读手册找到-n。无论如何,tac才是我真正想要的。 - Greg Hewgill

1
awk '{a[i++]=$0}END{for(;i-->0;)print a[i]}'

sed 更快,并且适用于嵌入式设备,如 openwrt。


1
:   "@(#)$Id: reverse.sh,v 1.2 1997/06/02 21:45:00 johnl Exp $"
#
#   Reverse the order of the lines in each file

awk ' { printf("%d:%s\n", NR, $0);}' $* |
sort -t: +0nr -1 |
sed 's/^[0-9][0-9]*://'

对我来说非常好用...


O(N.log(N))与O(N) tacsed=你能想到的最不有效的方法吗?我认为可能会有O(N!),试着找出来。 - Hynek -Pichi- Vychodil
我通常每个月会使用它几次,主要是在几百行代码以内。对于这种情况来说,它表现得很好。如果我需要每天处理千兆字节的文件,那么我会重新考虑。这段代码是我在1989年编写的,1997年我修改了ID字符串表示法。它是稳定的代码。而且,在Solaris上'tac'不是标准命令。 - Jonathan Leffler
但是我猜在Solaris上有sed,因此您可以使用更有效的sed 'x;1!H;$!d;x'。 - Hynek -Pichi- Vychodil
可能 - 我不使用它来处理如此大的文件,以至于排序需要将数据溢出到磁盘,但如果没有足够的内存空间供其使用,则sed版本会崩溃。如果这是性能问题,我会考虑移动; 对我来说不是(性能问题),所以我可能太懒了,不想改变。 - Jonathan Leffler
没错。sed不像sort那样将数据缓存到磁盘中。我不知道tac是否受到同样的错误影响;-) - Hynek -Pichi- Vychodil

0
rev <name of your text file.txt>

你甚至可以这样做:

echo <whatever you want to type>|rev

这是对一个不同问题的很好的回答。 rev 命令可以反转每行文字;但是楼主寻找的是 tac 命令,它会打印最后一行首先显示,然后是倒数第二行,以此类推。 - tripleee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接