Procure um arquivo e imprima o texto de linhas específicas

8

Eu tenho um arquivo com os dados que eu salvo. Agora eu gostaria de imprimir meus resultados em um novo arquivo.

Por exemplo, vamos pegar este exemplo randomlog.log:

Link encap:Ethernet HWaddr 08:00:00:00:00:67
inet addr:10.10.10.10 Bcast:10.10.10.10 Mask:255.255.255.0
inet6 addr: fe80::casf:sdfg:23ra:dg12/64 Scope:Link

Como posso pegar apenas dados do 12º ao 20º caracteres da primeira linha e depois do 4º ao 8º caracteres da 3ª linha? Saída seria algo parecido com isto:

Ethernet
t6 ad

Isso é possível? Eu quero definir a linha e de posição para esta posição.

Insanebench420
fonte

Respostas:

9

Aqui está uma sedabordagem:

$ sed -nE '1s/.{11}(.{8}).*/\1/p; 3s/.{3}(.{4}).*/\1/p' file  
Ethernet
t6 a

Explicação

A -nsaída normal suprime (normal é imprimir cada linha de entrada) para que ele imprime apenas quando solicitado. O -Epermite expressões regulares estendidas.

O sedscript possui dois comandos, ambos usando o operador de substituição ( s/original/replacement/). Ele 1s/.{11}(.{8}).*/\1/pserá executado apenas na 1ª linha (é o que 1sfaz) e corresponderá aos 11 primeiros caracteres da linha ( .{11}), depois capturará os próximos 8 ( (.{8})os parênteses são um "grupo de captura") e depois todo o resto até o fim da linha ( .*). Tudo isso é substituído pelo que estava no grupo de captura ( \1; se houvesse um segundo grupo de captura, seria \2etc.). Finalmente, pno final ( s/foo/bar/p) faz com que a linha seja impressa após a substituição. Isso resulta apenas na saída dos 8 caracteres de destino.

O segundo comando é a mesma idéia geral, exceto que ele será executado apenas na 3ª linha ( 3s) e manterá os 4 caracteres começando no 4º.


Você também pode fazer o mesmo com perl:

$ perl -ne 'if($.==1){s/.{11}(.{8}).*/\1/}
            elsif($.==3){s/.{3}(.{4}).*/\1/}
            else{next}; print; ' file 
Ethernet
t6 a

Explicação

Os -nemeios "lêem o arquivo de entrada linha por linha e aplicam o script fornecido por -ecada linha. O script é a mesma ideia básica de antes. A $.variável mantém o número da linha atual, portanto verificamos se o número da linha é 1ou 3e, se portanto, execute a substituição, caso contrário, pule.Portanto, printele será executado apenas para essas duas linhas, pois todas as outras serão ignoradas.


Claro, esse é o Perl, então o TIMTOWTDI :

$ perl -F"" -lane '$. == 1 && print @F[11..19]; $.==3 && print @F[3..6]' file 
Ethernet 
t6 a

Explicação

Aqui, os -ameios "dividem cada linha de entrada no caractere fornecido por -Fe salvam como a matriz @F. Como o caractere fornecido está vazio, isso salvará cada caractere da linha de entrada como um elemento @F. Em seguida, imprimimos os elementos 11-19 ( matrizes começam a contar em 0) para a 1ª linha e 3-7 na 3ª.

Terdon
fonte
1

abordagem awk:

$ awk 'NR==1{print substr($0,12,8)};NR==3{print substr($0,4,4)}' input.txt  
Ethernet
t6 a

Usa NRpara determinar o número da linha (na terminologia awk - registro) e, consequentemente, imprimir a subcadeia da linha. substr()função está no formato

substr(string,starting position,how much offset) 

Pitão

$ python -c 'import sys                                                                                                                                                
> for index,line in enumerate(sys.stdin,1):                                                                                                                            
>     if index == 1:
>          print line[11:19]
>     if index == 3:
>          print line[3:7]' < input.txt
Ethernet
t6 a

Isso usa o <operador shell para redirecionar o fluxo de entrada para o processo python a partir do arquivo de entrada. Observe que as strings em python são indexadas em 0; portanto, você precisa alterar o número de caracteres desejado em 1.

maneira shell portátil

Isso funciona em ksh, dash, bash. Depende apenas de utilitários de shell, nada de externo.

#!/bin/sh

rsubstr(){
    i=0;
    while [ $i -lt  $2 ];
    do
        rmcount="${rmcount}?"
        i=$(($i+1))
    done;
    echo "${1#$rmcount}"
}

lsubstr(){
    printf "%.${2}s\n" "$1"
}

line_handler(){
    case $2 in
        1) lsubstr "$(rsubstr "$1" 11)" 8 ;;
        3) lsubstr "$(rsubstr "$1" 3)" 5 ;;
    esac
}

readlines(){
    line_count=1
    while IFS= read -r line;
    do
        line_handler "$line" "$line_count"
        line_count=$(($line_count+1))
    done < $1
}

readlines "$1"

E funciona assim:

$ ./get_line_substrings.sh input.txt                                                                                                                                   
Ethernet
t6 ad
Sergiy Kolodyazhnyy
fonte