Jim Meyering wrote: > That is an option no GNU system needs, since they've all had tac since > before 1992-era textutils.
But 'tac' does not have a line-number-limit argument. The POSIX rationale [1] has "While both tail -n$n | tac and tac | head -n$n can be used to output a fixed length of reversed line output, the standard developers decided that it was preferable to have a single utility tail -r -n$n for the same purpose." The second of these alternatives, 'tac | head -n$n' will not work well with non-seekable files: it requires 'tac' to buffer the *entire* input (as huge as it may be), before extracting a few lines of it. The first alternative looks better: 'tail -n$n | tac'. But thinking through it, it seems the logic that 'tail' uses for 'tail -n$n' is also nearly suitable for 'tail -r -n$n': - In function file_lines(), instead of calling dump_remainder at the end, the loop would call xwrite_stdout once for each line (with special considerations for lines that span more than 1 buffer). - In function pipe_lines(), all the relevant data is in memory at the end. It's only a question of doing the xwrite_stdout calls on smaller pieces and in reverse order. When implemented this way, this will be more efficient than to spawn 'tac' as a separate subprocess. Collin Funk wrote: > But I agree that duplicating parts of 'tac' into > 'tail' does not seem ideal. Which parts of the 'tac' program would need to be reused in 'tail'? Maybe the output() function? In any case, the technique for avoiding code duplication is well-known. The programs 'cp', 'mv', 'install' have overlapping functionality without necessitating duplicated code. Bruno [1] https://pubs.opengroup.org/onlinepubs/9799919799/utilities/tail.html