Estou com uma longa lista de endereços IP, que não estão em sequência. Preciso descobrir quantos endereços IP existem antes / depois de um endereço IP específico. Como posso conseguir isso?
Estou com uma longa lista de endereços IP, que não estão em sequência. Preciso descobrir quantos endereços IP existem antes / depois de um endereço IP específico. Como posso conseguir isso?
Respostas:
Talvez o mais fácil seja,
sed -n '/pattern/{=; q;}' file
Obrigado @JoshepR por apontar o erro
dc
mim, provavelmente.
Fiz isso de duas maneiras, apesar de achar que gosto mais disso:
: $(( afterl=( lastl=$(wc -l <~/file) ) - 2 -
$(( beforel=( matchl=$(sed -n "/$IP/{=;q;}" <~/file) ) - 1
)) ))
for n in last match afters befores
do printf '%s line%s :\t%d\n' \
"${n%s}" "${n##*[!s]}" $((${n%s}l))
done
Isso salva todas elas como variáveis atuais do shell - e as avalia no loop for posteriormente para a saída. Ele conta o total de linhas no arquivo com wc
e obtém o primeiro número de linha correspondente sed
.
Sua saída:
last line : 1000
match line : 200
after lines : 799
before lines : 199
Eu também fiz:
sed -n "/$IP/=;\$=" ~/file |
tr \\n \ | {
IFS=' ' read ml ll
printf '%s line%s:\t%d\n' \
last '' $((ll=${ll##* }))
match '' $ml \
after s "$((al=ll-ml-1)) \
before s $((bl=ml-1))
}
sed
imprime apenas números correspondentes e da última linha e, em seguida, tr
converte as \n
linhas eletrônicas intermediárias eme read
lê o primeiro dos sed
resultados de $ml
e todos os outros $ll
. Possíveis casos de correspondência múltipla são tratados removendo todos os resultados, exceto o último, da $ll
expansão ao configurá-los novamente mais tarde.
Sua saída:
last line : 1000
match line : 200
after lines : 799
before lines : 199
Ambos os métodos foram testados no arquivo gerado da seguinte maneira:
IP='some string for which I seek'
for count in 1 2 3 4 5
do printf '%.199d%s\n' 0 "$IP"
done | tr 0 \\n >~/file
Sim, pelo número da linha:
"$IP"
depois uma linha de \n
ewtr
- que traduz zeros em \n
linhas de e-mail e depois em~/file
Aqui está um pouco do código Perl que faz isso:
perl -ne '
if(1 .. /192\.168\.1\.1/) { $before++ }
else { $after++ }
$before--; # The matching line was counted
END{print "Before: $before, After: $after\n"}' your_file
Isso conta o número total de linhas antes e depois da linha que contém o IP 192.168.1.1
. Substitua pelo seu IP desejado.
Usando nada além do Bash:
before=0
match=0
after=0
while read line;do
if [ "$line" = 192.168.1.1 ];then
match=1
elif [ $match -eq 0 ];then
before=$(($before+1))
else
after=$(($after + 1))
fi
done < your_file
printf "Before: %d, After: %d\n" "$before" "$after"
$.
vez de um contador?
$after
de $. - $before
.
$. - 1
, salve $.
em $tmp
. Finalize a impressão $. - $tmp
. Portanto, não precisamos de contador para antes e depois. Claro que é menos legível que o seu.
Eu estava tentando os seguintes comandos, que são um pouco complicados, mas dariam resultados precisos:
Depois de:
a=$(cat file | wc -l) && b=$(cat -n file | grep <Pattern> | awk '{print $1}') && echo "$a - $b" | bc -l
Antes:
echo "`cat -n file | grep <Pattern> | awk '{print $1}'`-1" | bc -l
Grep
possui um recurso que pode contar o número de vezes que um padrão específico é encontrado. Se você usar o -c
comando que fará isso. Com o comando -c
e -v
, isso contará quantas vezes isso não corresponde a um padrão específico
Exemplo:
grep -c -v <pattern> file
Então, se você tentar algo como:
grep -c -v 192.168.x.x file.log
isso deve funcionar.