如何从文件向后打印行(不使用“tac”)?

32 shell text-processing

我想在不使用tac命令的情况下向后打印文件中的行。有没有其他解决方案可以用 bash 做这样的事情?

Joh*_*web 43

使用sed效仿tac:

sed '1!G;h;$!d' "${inputfile}"
Run Code Online (Sandbox Code Playgroud)

  • 这是一个著名的“sed”单行。请参阅“36. 颠倒行序(模拟“tac”Unix 命令)。在 [Famous Sed One-Liners Explained](http://www.catonmat.net/blog/sed-one-liners-explained-part-one/) 中对其工作原理的完整解释。 (15认同)
  • 这是一个很好的解决方案,但对其如何工作的一些解释会更好。 (7认同)
  • 也许值得注意的是:“这两个单行实际上使用了大量内存,因为它们在打印出来之前将整个文件以相反的顺序保存在保持缓冲区中。对于大文件避免使用这些单行。” (7认同)

don*_*sti 11

与ed:

ed -s infile <<IN
g/^/m0
,p
q
IN
Run Code Online (Sandbox Code Playgroud)

如果你在BSD/ OSX(希望很快也在GNU/ 上linux,因为它将是 POSIX):

tail -r infile
Run Code Online (Sandbox Code Playgroud)


Mar*_*try 6

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

通过awk 一个班轮

  • 更短的一个:`awk 'a=$0RS a{}END{printf a}'` (4认同)
  • 或者 `awk '{a[NR]=$0} END {while (NR) print a[NR--]}'` (3认同)

phi*_*lfr 6

当您要求在 bash 中执行此操作时,这里有一个不使用 awk、sed 或 perl 的解决方案,只是一个 bash 函数:

reverse ()
{
    local line
    if IFS= read -r line
    then
        reverse
        printf '%s\n' "$line"
    fi
}
Run Code Online (Sandbox Code Playgroud)

的输出

echo 'a
b
c
d
' | reverse
Run Code Online (Sandbox Code Playgroud)

是

d
c
b
a
Run Code Online (Sandbox Code Playgroud)

正如预期的那样。

但请注意,行存储在内存中,每个递归调用的函数实例中都有一行。所以对大文件要小心。

  • 与其他答案中最慢的相比,随着文件大小的增加,它很快变得不切实际,并且正如您所建议的那样,它很容易消耗内存:*bash 递归函数......但它是一个有趣的想法。分段故障 * (3认同)

小智 5

你可以通过管道:

awk '{print NR" "$0}' | sort -k1 -n -r | sed 's/^[^ ]* //g'
Run Code Online (Sandbox Code Playgroud)

awk每一行的前缀为行号,后跟一个空格。通过以sort相反的数字样式对第一个字段(行号)进行排序来反转行的顺序。并sed剥离行号。

以下示例显示了这一点:

pax$ echo 'a
b
c
d
e
f
g
h
i
j
k
l' | awk '{print NR" "$0}' | sort -k1 -n -r | sed 's/^[^ ]* //g'
Run Code Online (Sandbox Code Playgroud)

它输出:

l
k
j
i
h
g
f
e
d
c
b
a
Run Code Online (Sandbox Code Playgroud)

  • `cat -n` 的作用很像 `awk '{print NR" "$0}'` (5认同)
  • 我认为这叫做 **Schwartzian 变换**,或 **decorate-sort-undecorate** (2认同)