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 pegar apenas dados do 12º ao 20º caractere da primeira linha e depois do 4º ao 8º caracteres da 3ª linha? A saída seria algo assim:
Ethernet
t6 ad
Isso é possível? Quero definir a linha e da posição para esta posição.
Responder1
Aqui está uma sed
abordagem:
$ sed -nE '1s/.{11}(.{8}).*/\1/p; 3s/.{3}(.{4}).*/\1/p' file
Ethernet
t6 a
Explicação
O -n
suprime a saída normal (o normal é imprimir todas as linhas de entrada) para que ela seja impressa apenas quando solicitado. O -E
permite expressões regulares estendidas.
O sed
script possui dois comandos, ambos utilizando o operador de substituição ( s/original/replacement/
). O 1s/.{11}(.{8}).*/\1/p
será executado apenas na primeira linha (é isso que 1s
faz) e corresponderá aos primeiros 11 caracteres da linha ( .{11}
), entãocapturaos próximos 8 ( (.{8})
, os parênteses são um "grupo de captura") e depois todo o resto até o final da linha ( .*
). Tudo isso é substituído pelo que estava no grupo de captura ( \1
; se houvesse um segundo grupo de captura, seria \2
etc.). Por fim, 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 na saída de apenas 8 caracteres de destino.
O segundo comando tem a mesma ideia geral, exceto que só será executado na 3ª linha ( 3s
) e manterá os 4 caracteres a partir da 4ª.
Você também pode fazer a mesma coisa 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 -ne
meios "ler o arquivo de entrada linha por linha e aplicar o script fornecido por -e
a cada linha. O script é a mesma ideia básica de antes. A $.
variável contém o número da linha atual, então verificamos se o número da linha é ou 1
e 3
, se então, execute a substituição, caso contrário, pule. Portanto, print
só será executado para essas duas linhas, pois todas as outras serão ignoradas.
Claro, este é Perl, entãoTIMTOWTDI:
$ perl -F"" -lane '$. == 1 && print @F[11..19]; $.==3 && print @F[3..6]' file
Ethernet
t6 a
Explicação
Aqui, -a
significa "dividir cada linha de entrada no caractere fornecido por -F
e salvar como a matriz @F
. Como o caractere fornecido está vazio, isso salvará cada caractere da linha de entrada como um elemento em @F
. Em seguida, imprimimos os elementos 11-19 ( matrizes começam a contar em 0
) para a 1ª linha e 3-7 para a 3ª.
Responder2
abordagem estranha:
$ 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 (na terminologia awk - registro) e, consequentemente, imprimir a substring da linha. substr()
a 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 do arquivo de entrada. Observe que as strings em python são indexadas em 0, portanto, você precisa mudar todos os números de caracteres desejados em 1.
maneira de concha portátil
Isso funciona em ksh
, dash
, bash
. Depende apenas de utilitários 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