如何倒转文件中行的顺序?

835

我想要反转一个文本文件(或stdin)中的行顺序,同时保留每行的内容。

也就是说,例如,从以下内容开始:

foo
bar
baz

我想最终拥有

baz
bar
foo

有没有标准的UNIX命令行实用程序可以做到这一点?


8
关于反转行的重要说明:首先要确保你的文件有一个尾随的换行符。否则,在输出文件中,输入文件的最后两行将合并为一行(至少使用 perl -e 'print reverse <>',但可能也适用于其他方法)。 - jakub.g
1
可能是如何反转文本文件的行?的重复问题。 - Greg Hewgill
这也几乎是一个重复的问题(尽管更旧),与http://unix.stackexchange.com/questions/9356/how-can-i-print-lines-from-file-backwards-without-using-tac相同。与那种情况一样,迁移到unix.stackexchange.com可能是适当的。 - mc0e
24个回答

12

我真的很喜欢"tail -r"的答案,但我最喜欢的gawk答案是....

gawk '{ L[n++] = $0 } 
  END { while(n--) 
        print L[n] }' file

在Ubuntu 14.04 LTS上使用mawk测试过 - 可以正常工作,因此不是GNU awk特定的。+1 - Sergiy Kolodyazhnyy
n++ can be replaced with NR - karakfa

11

最简单的方法是使用tac命令。taccat的反向命令。 示例:

$ cat order.txt
roger shah 
armin van buuren
fpga vhdl arduino c++ java gridgain
$ tac order.txt > inverted_file.txt
$ cat inverted_file.txt
fpga vhdl arduino c++ java gridgain
armin van buuren
roger shah 

2
不确定为什么这个答案会在下面那个之前出现,但它是 https://dev59.com/g3RB5IYBdhLWcg3wCjcV#742485 的副本,而后者是几年前发布的。 - anarcat

9
如果您想直接修改文件,可以运行以下命令:
sed -i '1!G;h;$!d' filename

这种方式不需要创建临时文件,也不需要删除或重命名原始文件,但是可以达到相同的效果。例如:

$tac file > file2
$sed -i '1!G;h;$!d' file
$diff file file2
$

根据ephemient的答案,这个答案几乎满足了我的需求,但还有些许不同。


4

编辑 下面是生成一个随机排序的1到10的数字列表的代码:

seq 1 10 | sort -R | tee /tmp/lst |cat <(cat /tmp/lst) <(echo '-------') **...**

在这里,点号将被实际命令替换,该命令可反转列表。

tac

seq 1 10 | sort -R | tee /tmp/lst |cat <(cat /tmp/lst) <(echo '-------') \
<(tac)

Python:使用 [::-1] 处理 sys.stdin

seq 1 10 | sort -R | tee /tmp/lst |cat <(cat /tmp/lst) <(echo '-------') \
<(python -c "import sys; print(''.join(([line for line in sys.stdin])[::-1]))")

3
这将适用于BSD和GNU。
awk '{arr[i++]=$0} END {while (i>0) print arr[--i] }' filename

2
我看到了很多有趣的想法,但是试试我的建议。将您的文本输入以下内容:

rev | tr '\n' '~' | rev | tr '~' '\n'

此命令假设文件中不存在字符“~”。这在追溯到1961年的每个UNIX shell上都可以使用。或者类似于此的命令。
"Original Answer"翻译成"最初的回答"

谢谢,这在我的MacOS上运行得非常好。cat foo.txt | rev | tr '\n' '~' | rev | tr '~' '\n' > bar.txt - Kerry Johnson

1
我遇到的问题是,我想要高效地获取一个非常大的文本文件的最后n行。首先我尝试使用tail -n 10000000 file.txt > ans.txt,但我发现它非常慢,因为tail必须查找位置,然后移动回来打印结果。当我意识到这一点时,我切换到另一个解决方案:tac file.txt | head -n 10000000 > ans.txt。这次,查找位置只需要从末尾移动到所需位置,它节省了50%的时间!带回家的信息是:如果您的tail没有-r选项,请使用tac file.txt | head -n n。

1
对于Emacs用户:使用C-x h(选择整个文件),然后使用M-x reverse-region。也适用于仅选择部分或行并将其反转。

1

您可以在命令行上使用Perl:

perl -e 'my @b=(); while(<>) {push(@b, $_);}; print join("", reverse(@b));' orig > rev


0
最佳解决方案:
tail -n20 file.txt | tac

欢迎来到Stack Overflow!虽然这段代码可能解决了问题,但包括解释真的有助于提高您的帖子质量。请记住,您正在为未来的读者回答问题,而这些人可能不知道您提出代码建议的原因。请尽量不要在代码中加入过多的解释性注释,这会降低代码和解释的可读性! - kayess
这些工具都有文档说明:人们必须在某个时候自己阅读 man tailman tac,而不是被喂到嘴里。+1 - Kaz

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