Olhe através de um arquivo e imprima o texto de linhas específicas

8

Eu tenho um arquivo com dados que salvo. Agora 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 obter apenas dados do 12º ao 20º caractere da primeira linha e, em seguida, do 4º ao 8º caracteres da 3ª linha? Saída seria algo como isto:

Ethernet
t6 ad

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

    
por Insanebench420 28.12.2016 / 14:07

2 respostas

9

Aqui está uma abordagem sed :

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

Explicação

O -n suprime a saída normal (o normal é imprimir todas as linhas de entrada) para que seja impresso somente quando for solicitado. O -E ativa expressões regulares estendidas.

O script sed tem dois comandos, ambos usando o operador de substituição ( s/original/replacement/ ). O 1s/.{11}(.{8}).*//p será executado somente na primeira linha (é o que o 1s faz) e corresponderá aos 11 primeiros caracteres da linha ( .{11} ), então captura os próximos 8 ( (.{8}) , os parênteses são um "grupo de captura") e depois todo o restante até o final da linha ( .* ). Tudo isso é substituído pelo que estava no grupo de captura ( ; se houvesse um segundo grupo de captura, seria etc.). Finalmente, o p no final ( s/foo/bar/p ) faz com que a linha seja impressa após a substituição ter sido feita. Isso resulta em apenas os 8 caracteres de destino sendo emitidos.

O segundo comando é a mesma idéia geral, exceto que ele será executado somente na terceira linha ( 3s ) e manterá os 4 caracteres a partir do quarto.

Você também pode fazer a mesma coisa com perl :

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

Explicação

O -ne significa "leia o arquivo de entrada linha a linha e aplique o script dado por -e a cada linha. O script tem a mesma idéia básica de antes. A variável $. contém o número da linha atual Verificamos se o número da linha é 1 ou 3 e, se for o caso, executamos a substituição, senão pulamos, portanto a print será executada apenas para essas duas linhas, pois todas as outras serão ignoradas.

Claro, isso é Perl, então TIMTOWTDI :

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

Explicação

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

    
por terdon 28.12.2016 / 14:38
1

abordagem awk:

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

Usa NR para determinar o número da linha (no registro de terminologia do awk) e, portanto, imprimir a substring da linha. A função substr() está no formato

substr(string,starting position,how much offset) 

Python

$ 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, é necessário alterar todos os números de caracteres desejados em 1.

caminho de shell portátil

Isso funciona em ksh , dash , bash . Depende apenas de utilitários de shell, nada 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
    
por Sergiy Kolodyazhnyy 04.11.2017 / 19:22