Como alinhar uma coluna em um arquivo de texto

4

Usando o bash no Linux, como posso processar um arquivo de texto de modo que o espaço seja inserido antes de uma determinada coluna, de modo que a coluna seja alinhada na saída? Por exemplo:

Entrada

1653455 ASDFASDF22 bla bla bla asd xmv ASDFASDF22 AA
1944444 ASDFASDF22 klasdfmxvl yxklc erisa ask xdk asdm ase ASDFASDF22 BB
1984945 ASDFASDF22 jklyck aklsdfl asfjasl asdkkcii wdkkkxd aslasl wqe ASDFASDF22 BB

Saída

1653455 ASDFASDF22 bla bla bla asd xmv                                ASDFASDF22 AA
1944444 ASDFASDF22 klasdfmxvl yxklc erisa ask xdk asdm ase            ASDFASDF22 BB
1984945 ASDFASDF22 jklyck aklsdfl asfjasl asdkkcii wdkkkxd aslasl wqe ASDFASDF22 BB

As colunas entre os dois ASDFASDF22 s devem ter menos de 50 caracteres ou devem ser truncadas.

    
por LanceBaynes 22.12.2011 / 18:27

6 respostas

5

Uma solução usando perl :

Conteúdo de script.pl :

use warnings;
use strict;

## Acept one argumnet, the input file.
@ARGV == 1 or die qq[Usage: perl $0 input-file\n];

while ( <> ) {
        ## Remove last '\n' char.
        chomp;

        ## Split line with string 'ASDFASDF22'
        my @f = split /(ASDFASDF22)/;

        ## Print line but print first 49 chars plus a space of the special string.
        printf qq[%s%-50s%s\n],
                join( qq[], @f[0,1] ),
                substr( $f[2], 0, 49 ) . qq[ ],
                join( qq[], @f[3..$#f] );
}

Execute o script:

perl script.pl infile

E saída:

1653455 ASDFASDF22 bla bla bla asd xmv                              ASDFASDF22 AA
1944444 ASDFASDF22 klasdfmxvl yxklc erisa ask xdk asdm ase          ASDFASDF22 BB
1984945 ASDFASDF22 jklyck aklsdfl asfjasl asdkkcii wdkkkxd aslasl w ASDFASDF22 BB
    
por 22.12.2011 / 19:12
2

Usando matrizes do bash

while read -r -a words; do
    prefix="${words[0]} ${words[1]}"
    idx=${#words[*]}
    suffix="${words[$((idx-2))]} ${words[$((idx-1))]}"
    unset words[0] words[1] words[$((idx-2))] words[$((idx-1))]
    middle="${words[*]}"
    printf "%s %-50s %s\n" "$prefix" "${middle:0:50}" "$suffix"
done < filename
    
por 22.12.2011 / 20:35
1

Eu tentei o script do @Birei em um arquivo de texto que eu precisava colocar em coluna, mas ele falhou porque o arquivo continha algumas linhas que não correspondiam ao delimitador fornecido (e não precisavam estar em colunas). Assim, com meu conhecimento pobre de perl, adicionei uma simples verificação do tamanho da matriz para evitar o processamento de linhas não correspondentes. Vou postar o código básico aqui no caso de alguém precisar dessa mudança.

use warnings;
use strict;

## Acept one argumnet, the input file.
@ARGV == 1 or die qq[Usage: perl $0 input-file\n];

while ( <> ) {
    ## Remove last '\n' char.
    chomp;

    ## Split line with string 'ASDFASDF22'
    my @f = split /(ASDFASDF22)/;

    my $f = @f;
    # check array size to avoid errors on non-matching lines
    if ($f > 1)
    {
        ## Print line but print first 49 chars plus a space of the special string.
        printf qq[%s%-50s%s\n],
                join( qq[], @f[0,1] ),
                substr( $f[2], 0, 49 ) . qq[ ],
                join( qq[], @f[3..$#f] );

   }
   else
   {
       # output non-matching line as-is
       print $_ . qq[\n];
   }
}

Então, como um exemplo da saída:

1653455 ASDFASDF22 bla bla bla asd xmv                              ASDFASDF22 AA
1944444 ASDFASDF22 klasdfmxvl yxklc erisa ask xdk asdm ase          ASDFASDF22 BB
######################### non-matching line left alone ##########################
1984945 ASDFASDF22 jklyck aklsdfl asfjasl asdkkcii wdkkkxd aslasl w ASDFASDF22 BB
    
por 07.08.2014 / 16:34
0
f=open("filename","r") 

a=[]

for line in f:

    if line[-1:]=='\n':
        line=line[:-1]

    a=line.split("ASDFASDF22")

    a.insert(1,"ASDFASDF22")

    a.insert(len(a)-1,"ASDFASDF22")

    k1=len(a[2])

    if k1 > 50:
        k2=k1-50
        k2=k2+1
        a[2]=a[2][:-k2]
        for i in a:
            print i,
    else:
        k2=50-k1
        for i in range(0,len(a)):
            if i !=2:
                print a[i],
            else:
                for j in range(0,k2):
                    a[2]=a[2]+" "
                print a[2],
    print ""'

Esta é uma implementação ingênua em python. Salve isso como filename.py e dê python filename.py .

    
por 22.12.2011 / 20:21
0

GNU awk:

awk -F "[[:space:]]+ASDFASDF22[[:space:]]+" \
    'BEGIN { OFS=" ASDFASDF22 "; }
    { 
        $2 = sprintf("%-50s", substr($2, 0, 50));
        print;
    }'
    
por 07.08.2014 / 17:57
0
while read -r one two line
do  printf "%s %s %-50.50s% %s\n" \   
       "$one" "$two" "${line%%"$two"*}" "$two${line#*"$two"}"         
done <<\DATA
1653455 ASDFASDF22 bla bla bla asd xmv ASDFASDF22 AA
1944444 ASDFASDF22 klasdfmxvl yxklc erisa ask xdk asdm ase ASDFASDF22 BB
1984945 ASDFASDF22 jklyck aklsdfl asfjasl asdkkcii wdkkkxd aslasl wqe ASDFASDF22 BB
1984945 ASDFASDF22 jklyck aklsdfl asfjasl asdkkcii wdkkkxd aslasl wqe hjbiub kuvyukvbklhb khuvbukvbuybouin ASDFASDF22 BB
DATA

Você pode fazer o acima com a maioria dos shell POSIX.

OUTPUT

1653455 ASDFASDF22 bla bla bla asd xmv                                ASDFASDF22 AA
1944444 ASDFASDF22 klasdfmxvl yxklc erisa ask xdk asdm ase            ASDFASDF22 BB
1984945 ASDFASDF22 jklyck aklsdfl asfjasl asdkkcii wdkkkxd aslasl wqe ASDFASDF22 BB
1984945 ASDFASDF22 jklyck aklsdfl asfjasl asdkkcii wdkkkxd aslasl wqe ASDFASDF22 BB
    
por 07.08.2014 / 17:36