How can I reverse the order of lines in a file?
我想颠倒文本文件(或stdin)中行的顺序,保留每行的内容。
所以,即从以下开始:
1 2 3 | foo bar baz |
我想结束
1 2 3 | baz bar foo |
是否有标准的UNIX命令行实用程序?
另外值得一提的是:
将一个文件翻转到另一个文件中
1 | tac a.txt > b.txt |
BSD尾巴:
1 | tail -r myfile.txt |
参考:FreeBSD,NetBSD,OpenBSD和OS X手册页。
有着名的sed技巧:
1 2 3 4 | # reverse order of lines (emulates"tac") # bug/feature in HHsed v1.5 causes blank lines to be deleted sed '1!G;h;$!d' # method 1 sed -n '1!G;h;$p' # method 2 |
(说明:在非初始行前加上保持缓冲区,交换行和保持缓冲区,在末尾打印出行)
或者(从更快的执行)来自awk单行:
1 | awk '{a[i++]=$0} END {for (j=i-1; j>=0;) print a[j--] }' file* |
如果你不记得了,
1 | perl -e 'print reverse <>' |
在具有GNU实用程序的系统上,其他答案更简单,但并非全世界都是GNU / Linux ......
如果你碰巧在
1 | :g/^/m0 |
1 | $ (tac 2> /dev/null || tail -r) |
尝试
1 | tac <file_name> |
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 | $ cat file1.txt 1 2 3 4 5 $ tac file1.txt 5 4 3 2 1 |
在你的命令结束时:
tac完全符合您的要求,它"将每个文件写入标准输出,最后一行写入。"
tac与猫相反:-)。
请尝试以下命令:
1 | grep -n"" myfile.txt | sort -r -n | gawk -F :"{ print $2 }" |
Just Bash :)(4.0+)
1 2 3 4 5 6 7 8 9 10 11 | function print_reversed { local lines i readarray -t lines for (( i = ${#lines[@]}; i--; )); do printf '%s '"${lines[i]}" done } print_reversed < file |
最简单的方法是使用
例:
1 2 3 4 5 6 7 8 9 | $ 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 |
我真的很喜欢"尾巴"答案,但我最喜欢的gawk答案是....
1 2 3 | gawk '{ L[n++] = $0 } END { while(n--) print L[n] }' file |
编辑
以下内容生成一个从1到10的随机排序的数字列表:
1 | seq 1 10 | sort -R | tee /tmp/lst |cat <(cat /tmp/lst) <(echo '-------') **...** |
其中点被替换为反转列表的实际命令
TAC
1 2 | seq 1 10 | sort -R | tee /tmp/lst |cat <(cat /tmp/lst) <(echo '-------') \ <(tac) |
python:在sys.stdin上使用[:: - 1]
1 2 | 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]))") |
对于可能在shell脚本中使用
1 2 3 4 | brew install coreutils echo"alias tac='gtac'">> ~/.bash_aliases (or wherever you load aliases) source ~/.bash_aliases tac myfile.txt |
这适用于BSD和GNU。
1 | awk '{arr[i++]=$0} END {while (i>0) print arr[--i] }' filename |
最佳方案:
1 | tail -n20 file.txt | tac |
如果要在适当的位置修改文件,可以运行
1 | sed -i '1!G;h;$!d' filename |
这样就无需创建临时文件,然后删除或重命名原始文件并具有相同的结果。例如:
1 2 3 4 | $tac file > file2 $sed -i '1!G;h;$!d' file $diff file file2 $ |
根据ephemient的答案,这几乎,但不完全,我想要的。
对于Emacs用户:
我看到很多有趣的想法。 但试试我的想法。 将文本管道输入:
rev | tr '
' '~' | rev | tr '~' '
'
假设字符'?'不在文件中。 这应该适用于每个回溯到1961年的UNIX shell。或类似的东西。
我有同样的问题,但我也希望第一行(标题)保持最佳状态。所以我需要使用awk的强大功能
1 | cat dax-weekly.csv | awk '1 { last = NR; line[last] = $0; } END { print line[1]; for (i = last; i > 1; i--) { print line[i]; } }' |
PS也适用于cygwin或gitbash
您可以使用
我们的想法是做以下事情:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | # Generate a newline delimited sequence of 1 to 10 $ seq 10 1 2 3 4 5 6 7 8 9 10 # Use - to read from stdin. # vim has a delay and annoying 'Vim: Reading from stdin...' output # if you use - to read from stdin. Use --not-a-term to hide output. # --not-a-term requires vim 8.0.1308 (Nov 2017) # Use -E for improved ex mode. -e would work here too since I'm not # using any improved ex mode features. # each of the commands I explained above are specified with a + sign # and are run sequentially. $ seq 10 | vim - --not-a-term -Es +'g/^/m0' +'%p' +'q!' 10 9 8 7 6 5 4 3 2 1 # non improved ex mode works here too, -e. $ seq 10 | vim - --not-a-term -es +'g/^/m0' +'%p' +'q!' # If you don't have --not-a-term, use /dev/stdin seq 10 | vim -E +'g/^/m0' +'%p' +'q!' /dev/stdin # POSIX compliant (maybe) # POSIX compliant ex doesn't allow using + sign to specify commands. # It also might not allow running multiple commands sequentially. # The docs say"Implementations may support more than a single -c" # If yours does support multiple -c $ seq 10 | ex -c"execute -c 'g/^/m0' -c '%p' -c 'q!' /dev/stdin # If not, you can chain them with the bar, |. This is same as shell # piping. It's more like shell semi-colon, ;. # The g command consumes the |, so you can use execute to prevent that. # Not sure if execute and | is POSIX compliant. seq 10 | ex -c"execute 'g/^/m0' | %p | q!" /dev/stdin |
如何使这个可重用
我使用一个脚本我调用
1 2 3 | #!/usr/bin/env sh vim - --not-a-term -Es"$@" +'%p | q!' |
我使用一个
然后你可以这样做:
1 | seq 10 | ved +'g/^/m0' |
如果您没有vim 8,请将其放在
1 2 3 | #!/usr/bin/env sh vim -E"$@" +'%p | q!' /dev/stdin |
tail -r适用于大多数Linux和MacOS系统
seq 1 20 |尾巴-r
1 | sort -r < filename |
要么
1 | rev < filename |