我想反转文本文件(或标准输入)中的行顺序,保留每行的内容。
所以,即,从:
foo
bar
baz
我想结束
baz
bar
foo
是否有一个标准的 UNIX 命令行实用程序来解决这个问题?
perl -e 'print reverse <>'
,但它可能也适用于其他方法)。
BSD尾巴:
tail -r myfile.txt
参考:FreeBSD、NetBSD、OpenBSD 和 OS X 手册页。
# 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
(说明:在非初始行前添加保存缓冲区,交换行和保存缓冲区,在末尾打印行)
或者(执行速度更快)from the awk one-liners:
awk '{a[i++]=$0} END {for (j=i-1; j>=0;) print a[j--] }' file*
如果你记不住,
perl -e 'print reverse <>'
在具有 GNU 实用程序的系统上,其他答案更简单,但并非全世界都是 GNU/Linux...
tail -r
和 tac 不可用。
tac
有望处理不适合内存的任意大文件(尽管行长度仍然有限)。目前尚不清楚 sed
解决方案是否适用于此类文件。
在你的命令末尾放:| tac
tac 完全符合您的要求,它“将每个文件写入标准输出,最后一行先。”
tac 是 cat 的对立面 :-)。
tac
命令的值,这对可能最终搜索同一主题的新用户很有用。
tac filename.ext
(cat filename.ext
的反转)
如果您碰巧在 vim
使用
:g/^/m0
tac <file_name>
例子:
$ cat file1.txt
1
2
3
4
5
$ tac file1.txt
5
4
3
2
1
$ (tac 2> /dev/null || tail -r)
尝试 tac
,它适用于 Linux,如果不起作用,请使用 tail -r
,它适用于 BSD 和 OSX。
tac myfile.txt
- 我错过了什么?
tac
不可用的情况下回退到 tail -r
。 tac
不符合 POSIX。 tail -r
也不是。仍然不是万无一失,但这提高了工作的可能性。
tac
可用,但内存不足并在消耗大量输入流的过程中进行交换,会发生什么情况。它失败了,然后 tail -r
成功地处理了流的其余部分,给出了不正确的结果。
brew install coreutils
并使用 gtac
代替 tac
,如果您更喜欢将 tac 添加为 gtac
的别名,例如您想要一个跨平台(Linux、OSX)使用它的 shell 脚本
尝试以下命令:
grep -n "" myfile.txt | sort -r -n | gawk -F : "{ print $2 }"
sed 's/^[0-9]*://g'
nl
将无法为空行编号。 -ba
选项在某些系统上可用,但不是通用的(想到 HP/UX,但我希望它不会),而 grep -n
将始终编号 每一 行匹配(在这种情况下为空)正则表达式。
cut -d: -f2-
而不是 gawk
只是重击 :) (4.0+)
function print_reversed {
local lines i
readarray -t lines
for (( i = ${#lines[@]}; i--; )); do
printf '%s\n' "${lines[i]}"
done
}
print_reversed < file
-nenenenenenene
的文件,并见证人们建议始终使用 printf '%s\n'
而不是 echo
的原因。
对于可能在 shell 脚本中使用 tac
的跨操作系统(即 OSX、Linux)解决方案,请使用上面其他人提到的自制软件,然后像这样使用别名 tac:
安装库
对于 MacOS
brew install coreutils
对于 linux debian
sudo apt-get update
sudo apt-get install coreutils
然后添加别名
echo "alias tac='gtac'" >> ~/.bash_aliases (or wherever you load aliases)
source ~/.bash_aliases
tac myfile.txt
最简单的方法是使用 tac
命令。 tac
是 cat
的逆。例子:
$ 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
我真的很喜欢“tail -r”的答案,但我最喜欢的 gawk 答案是......
gawk '{ L[n++] = $0 }
END { while(n--)
print L[n] }' file
mawk
测试 - 有效,因此它不是 GNU awk 特定的。 +1
n++
可以替换为 NR
如果要就地修改文件,可以运行
sed -i '1!G;h;$!d' filename
这消除了创建临时文件然后删除或重命名原始文件的需要,并且具有相同的结果。例如:
$tac file > file2
$sed -i '1!G;h;$!d' file
$diff file file2
$
基于 answer by ephemient,它几乎但不完全是我想要的。
编辑以下生成从 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:在 sys.stdin 上使用 [::-1]
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]))")
这将适用于 BSD 和 GNU。
awk '{arr[i++]=$0} END {while (i>0) print arr[--i] }' filename
我看到了很多有趣的想法。但是试试我的想法。将您的文本输入:
转 | tr '\n' '~' |转 | tr '~' '\n'
它假定字符“~”不在文件中。这应该适用于可以追溯到 1961 年的每个 UNIX shell。或者类似的东西。
cat foo.txt | rev | tr '\n' '~' | rev | tr '~' '\n' > bar.txt
对于 Emacs 用户:C-x h
(选择整个文件)然后是 M-x reverse-region
。也适用于仅选择零件或线条并恢复它们。
我碰巧想有效地获取一个非常大的文本文件的最后 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
。
您可以在命令行上使用 Perl:
perl -e 'my @b=(); while(<>) {push(@b, $_);}; print join("", reverse(@b));' orig > rev
最佳解决方案:
tail -n20 file.txt | tac
您可以使用 vim
stdin
和 stdout
来完成。您也可以使用 ex
作为 POSIX compliant。 vim
只是 ex
的可视模式。事实上,您可以将 ex
与 vim -e
或 vim -E
一起使用(改进的 ex
模式)。 vim
很有用,因为与 sed
之类的工具不同,它缓冲文件以供编辑,而 sed
用于流。您也许可以使用 awk
,但您必须手动缓冲变量中的所有内容。
想法是执行以下操作:
从标准输入读取每行将其移动到第 1 行(反转)。命令是 g/^/m0。这意味着全局,对于每一行 g;匹配行首,匹配任何内容 ^;将其移到地址 0 之后,即第 1 行 m0。打印一切。命令是 %p。这意味着对于所有行的范围 %;打印第 p 行。强制退出而不保存文件。命令是 q!。这意味着退出 q;强行!
# 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
如何使这个可重复使用
我使用称为 ved
的脚本(类似 sed
的 vim 编辑器)使用 vim 编辑 stdin
。将此添加到路径中名为 ved
的文件中:
#!/usr/bin/env sh
vim - --not-a-term -Es "$@" +'%p | q!'
我使用的是一个 +
命令而不是 +'%p' +'q!'
,因为 vim 将您限制为 10 个命令。因此合并它们允许 "$@"
有 9 个 +
命令而不是 8 个。
然后你可以这样做:
seq 10 | ved +'g/^/m0'
如果您没有 vim 8,请将其放在 ved
中:
#!/usr/bin/env sh
vim -E "$@" +'%p | q!' /dev/stdin
rev
text here
或者
rev <file>
或者
rev texthere
tail -r 适用于大多数 Linux 和 MacOS 系统
序列 1 20 |尾 -r
sort -r < filename
或者
rev < filename
sort -r
仅在输入已排序时才有效,此处并非如此。 rev
反转每行的字符,但保持行顺序不变,这也不是 Scotty 所要求的。所以这个答案实际上根本就没有答案。
brew install coreutils
安装 tac(默认安装为gtac
)。echo -n "abc\ndee" > test; tac test
。