我想反转文本文件(或stdin)中的行顺序,保留每行的内容。
因此,即从:
foo
bar
baz
我想结束
baz
bar
foo
为此有标准的UNIX命令行实用程序吗?
我想反转文本文件(或stdin)中的行顺序,保留每行的内容。
因此,即从:
foo
bar
baz
我想结束
baz
bar
foo
为此有标准的UNIX命令行实用程序吗?
Answers:
brew install coreutils
(gtac
默认安装为)安装tac 。
echo -n "abc\ndee" > test; tac test
。
有著名的sed技巧:
# 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单行代码中(以更快的速度执行):
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
命令的值,这对于可能最终搜索同一主题的新用户很有用。
如果您碰巧正在vim
使用中
:g/^/m0
$ (tac 2> /dev/null || tail -r)
试试tac
,它在Linux上有效,如果不起作用,请使用tail -r
,它在BSD和OSX上有效。
tac myfile.txt
-我想念什么?
tail -r
以防万一tac
无法使用。tac
不符合POSIX。都不是tail -r
。仍然不是万无一失,但这可以提高工作的几率。
tac
可用,会发生什么,但会用完RAM,并在消耗大量输入流的过程中进行交换。它失败,然后tail -r
成功处理剩余的流,并给出错误的结果。
brew install coreutils
并使用它gtac
来代替tac
tac作为别名gtac
(例如,如果您想要一个跨平台使用它的shell脚本(Linux,OSX))
尝试以下命令:
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-
Just Bash :)(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
。
最简单的方法是使用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
在Ubuntu 14.04 LTS上进行过测试-可以正常运行,因此它不是特定于GNU AWK的。+1
n++
可以替换为NR
编辑 以下内容将生成一个随机排序的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]))")
对于可能使用的跨OS(即OSX,Linux)解决方案 tac
在shell脚本中使用的如上面其他人所述,请使用自制程序,然后使用别名tac如下所示:
安装lib
对于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
最佳解决方案:
tail -n20 file.txt | tac
对于Emacs用户:(C-x h
选择整个文件),然后单击M-x reverse-region
。也仅适用于选择零件或线并将其还原。
我有同样的问题,但我也希望第一行(标题)保持在最前面。所以我需要使用awk的力量
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\n20\n19...2\n
而不是20\n19...\2\n1\n
。
您可以使用vim
stdin
和进行操作stdout
。您还可以使用ex
要符合POSIX标准。vim
只是的视觉模式ex
。事实上,你可以使用ex
带有vim -e
或vim -E
(改进的ex
模式)。
vim
之所以有用,是因为sed
与之类似的工具不同,它缓冲文件以供编辑,而sed
用于流。您也许可以使用awk
,但是必须手动将所有内容缓冲在变量中。
该想法是要执行以下操作:
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
(如vim编辑器sed
)来使用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
sort -r < filename
要么
rev < filename
sort -r
仅在输入已经排序的情况下才有效,在此情况下不是这样。rev
反转每行的字符,但保持行序不变,这也不是Scotty要求的。因此,这个答案实际上根本没有答案。
perl -e 'print reverse <>'
但它可能也适用于其他方法)。