Seqüência reversa de um arquivo com ferramentas POSIX?

4

Existe algum equivalente POSIX limpo e claro para tac ?

A legibilidade e a sucessão devem ser consideradas.

    
por Wildcard 03.05.2016 / 01:21

4 respostas

1

O equivalente mais limpo POSIX seria

tail -r

como

-r          Reverse. Copies lines from the specified starting point in
            the file in reverse order. The default for r is to print the
            entire file in reverse order.

foi aceito para o próximo POSIX (e, com sorte, será logo será suportado em todas as plataformas).

Se tail -r não estiver disponível, as ferramentas de processamento de texto "clássicas" poderão ser usadas com êxito - como você e outros mostraram - para inverter as linhas em um arquivo.
Legibilidade e concisão à parte, mesmo o antigo ed pode fazer isso:

ed -s infile <<\IN
g/^/m0
,p
q
IN

ou, se for a saída de um pipeline que você deseja reverter - leia primeiro o buffer de texto:

ed -s <<\IN
r ! your | pipeline | goes | here
g/^/m0
,p
q
IN
    
por 26.01.2017 / 20:42
3

Aqui está um script awk que armazena o arquivo inteiro na memória:

awk '{line[NR]=$0} END {for (i=NR; i>=1; i--) print line[i]}' file

Frase como uma função shell:

tac () { awk '{line[NR]=$0} END {for (i=NR; i>=1; i--) print line[i]}' "$@"; }
    
por 03.05.2016 / 03:39
2

Você pode fazer isso com um sed one-liner da seguinte maneira, embora certamente não seja legível para os "não iniciados":

sed -n '1h;1!{x;H;};${g;p;}' file.txt

Explicação:

-n suprime a ação padrão de sed de imprimir cada linha.

1h faz com que a primeira linha seja armazenada no espaço de espera.

1!{...} aplica este bloco de comandos a todas as linhas exceto para o primeiro.

x troca o espaço de espera e o espaço de padrão. (O espaço de padrão é onde cada linha é armazenada enquanto está sendo processada.) Em seguida, H anexa ao espaço de espera uma nova linha seguida do (novo) conteúdo do espaço de padrão.

O bloco final ${...} só é aplicado quando a última linha é atingida. g obtém o conteúdo do espaço de armazenamento e o coloca no espaço padrão, e p imprime o espaço do padrão.

Claro que isso depende de ser capaz de manter o arquivo inteiro na memória de uma só vez; pode falhar em arquivos extremamente grandes.

    
por 03.05.2016 / 01:21
1

Aqui está uma solução POSIX clara clean para arquivos em disco:

#!/bin/sh
function tac () {
  lines=$(wc -l < "$1")
  while [ $lines -gt 0 ]
  do
    head -n $lines "$1" | tail -n 1
    lines=$((lines-1))
  done
}

O principal lado negativo é que ele lê o arquivo uma vez para cada linha no arquivo. POSIX não especifica um limite superior para -n number arquivos tão grandes podem invadir a escolha de uma implementação. O POSIX limita expansão aritmética ao número inteiro longo assinado (cerca de 2.147.483.647).

Uma construção semelhante pode ser feita a partir de tail -n -$lines input | head -n 1 .

Dado o requisito de ler o arquivo tantas vezes, elas provavelmente terão menos desempenho que tac .

    
por 03.05.2016 / 02:50