Reordenando strings no Linux

Reordenando strings no Linux

Como posso alterar as linhas usando a linha de comando?
por exemplo, eu tenho estas linhas:

    Acct-Status-Type = Start
    User-Name = "37XXXXXXX"
    Event-Timestamp = "Apr 12 2013 15:56:55 AMT"

Preciso mudar a ordem para isso:

    Event-Timestamp = "Apr 12 2013 15:56:55 AMT"
    User-Name = "37XXXXXXX"
    Acct-Status-Type = Start

Preciso fazer isso com um comando, sed, awk, perl ou algo parecido.

Responder1

Depende de onde, com que frequência, por que você faz isso, mas não faria mal nenhum colocá-lo em um script.

De qualquer forma, você poderia fazer algo assim para imprimir em ordem definida. Com esta abordagem, você também pode optar por imprimir apenas alguns selecionados. Por exemplo, apenas 1 e 3:

Um forro:

awk -v order=312 \
'/^/{ln[NR]=$0}END{split(order,a,"");
 for(i in a)printf("%s\n",ln[a[i]]);}' \
 sample.txt

Ou mais fácil de ler:

/^/{
    ln[NR] = $0
}
END{
    split(order,a,"");

    for(i in a)
        printf("%s\n",ln[a[i]]);
}

Para a divisão, você pode adicionar algum delimitador se tiver mais de 9 linhas.

Por exemplo:

split(order,a,"-");
# and call by:
awk -v order=3-13-21-12-2 ...

Ou para oferecer suporte a vários:

if (order ~ /-/)       split(order, a, "-"); # order has "-", split
else if (order ~ /\./) split(order, a, "."); # order has ".", split
else if (order ~/:/)   split(order, a, ":"); # order has ":", split
else                   split(order, a, "");  # none presume numbers split all

Você também pode optar por combinar linhas como em:

BEGIN {
    i = 0;
}
/^\s*Acct-Status-Type/ {ln[++i] = $0 }
/^\s*User-Name/ {ln[++i] = $0 }
/^\s*Event-Timestamp/ {ln[++i] = $0 }
END {
    if (order ~ /-/)  split(order, a, "-");
    else if (order ~ /\./) split(order, a, ".");
    else if (order ~/:/) split(order, a, ":");
    else split(order, a, "")
    for (i in a)
        printf("%s\n", ln[a[i]]);
}

Editar:

Para a última amostra, isso provavelmente seria melhor. (Também atualizou odividir):

/^\s*Acct-Status-Type/ {ln[1] = $0 }
/^\s*User-Name/ {ln[2] = $0 }
/^\s*Event-Timestamp/ {ln[3] = $0 }
END {
    if (split(order, a, "-|:|,| |\\.") == 1) # Space require quoting of arg.
        split(order, a, "")
    for (i in a)
        printf("%s\n", ln[a[i]]);
}

Responder2

Com Python e o nome do arquivo como parâmetro de linha de comando do programa:

import sys
with open(sys.argv[1]) as fp:
    for line in fp.readlines()[::-1]:
        sys.stdout.write(line)

ou gravá-lo de volta nesse arquivo:

import sys
with open(sys.argv[1]) as fp:
    lines = fp.readlines()
with open(sys.argv[1], 'w') as fp:
    for line in lines[::-1]:
        fp.write(line)

ou como um filtro de stdin para stdout:

lines = sys.stdin.readlines()
for line in lines[::-1]:
    sys.stdout.write(line)

informação relacionada