Suponho que você esteja fazendo isso em um loop de shell sobre todos os endereços IP, possivelmente com os endereços IP provenientes de um arquivo de texto. Sim, isso seria lento, com uma invocação de sed
ou grep
por endereço IP.
Em vez disso, você pode usar um único uso de sed
, se você se preparar com cuidado.
Primeiro, temos que criar um script sed
, e fazemos isso de um arquivo ip.list
que contém os endereços IP, um endereço por linha:
sed -e 'h' \
-e 's/\./\./g' \
-e 's#.*#/^&[[:blank:]]/w /tmp/access-#' \
-e 'G' \
-e 's/\n//' \
-e 's/$/.log/' ip.list >ip.sed
Esse sed
stuff, para cada endereço IP,
- Copie o endereço para o "espaço de armazenamento" (um buffer extra em
sed
). - Altere
.
no "espaço padrão" (a linha de entrada) em\.
(para corresponder aos pontos corretamente, seu código não fez isso). - Prefixe
^
e anexe[[:blank:]]/w /tmp/access-
ao espaço padrão. - Anexe a linha de entrada não modificada do espaço de suspensão ao espaço de padrão com uma nova linha no meio.
- Excluir essa nova linha.
- Anexe o
.log
ao final da linha (e implique o resultado implicitamente).
Para um arquivo que contenha
127.0.0.1
10.0.0.1
10.0.0.100
isso criaria o script sed
/^127\.0\.0\.1[[:blank:]]/w /tmp/access-127.0.0.1.log
/^10\.0\.0\.1[[:blank:]]/w /tmp/access-10.0.0.1.log
/^10\.0\.0\.100[[:blank:]]/w /tmp/access-10.0.0.100.log
Observe que você terá que corresponder a um caractere em branco (espaço ou tabulação) após o endereço IP, caso contrário, as entradas de log para 10.0.0.100
entrariam no arquivo /tmp/access-10.0.0.1.log
. Seu código omitiu isso.
Isso pode ser usado no seu arquivo de log (sem loop):
sed -n -f ip.sed /var/log/http/access.log
Eu nunca testei a gravação em 1200 arquivos de um mesmo script sed
. Se não funcionar, tente a variação abaixo de awk
.
Uma solução semelhante com awk
envolve a leitura dos endereços IP em uma matriz primeiro e, em seguida, a correspondência deles em cada linha. Isso requer uma única invocação awk
:
awk 'FNR == NR { list[$1] = 1; next }
$1 in list { name = $1 ".log"; print >>name; close name }' ip.list /var/log/http/access.log
Aqui, damos awk
a lista de IPs e o arquivo de log ao mesmo tempo. Quando NR == FNR
sabemos que ainda estamos lendo o primeiro arquivo (a lista), e adicionamos os números de IP às chaves list
as da matriz associativa e continuamos com a próxima linha de entrada.
Se a condição FNR == NR
não for verdadeira, estamos lendo o segundo arquivo (o arquivo de log) e testamos se o primeiro campo da linha de entrada é uma chave em list
(é uma planície comparação de string, não uma correspondência de expressão regular). Se for, anexamos a linha ao arquivo apropriadamente nomeado.
Precisamos ter cuidado ao fechar o arquivo de saída, pois, de outra forma, poderíamos ficar sem descritores de arquivos abertos. Portanto, haverá muitos arquivos de abertura e fechamento para anexar, mas ainda será mais rápido do que chamar awk
(ou qualquer utilitário) uma vez por endereço IP.
Eu estaria interessado em saber se essas coisas funcionam para você e qual pode ser o tempo de execução aproximado. Eu testei as soluções apenas em conjuntos extremamente pequenos de dados.
Claro, poderíamos ir com a sua ideia de apenas brute forçando-o a lançar várias instâncias de, e. grep
no sistema em paralelo:
Ignorando o fato de que não combinamos os pontos nos endereços IP corretamente, poderíamos fazer algo como
xargs -P 4 -n 100 sh -c '
for n do
grep "^$n[[:blank:]]" /var/log/http/access.log >"/tmp/access-$n.log"
done' sh <ip.list
Aqui, xargs
dará no máximo 100 endereços IP por vez do arquivo ip.list
para um script de shell curto. Ele irá organizar com quatro invocações paralelas do script.
O script de shell curto:
for n do
grep "^$n[[:blank:]]" /var/log/http/access.log >"/tmp/access-$n.log"
done
Isso apenas itera nos 100 endereços IP que xargs
fornece em sua linha de comando e aplica praticamente o mesmo comando grep
que você tinha, a diferença é que haverá quatro desses loops sendo executados em paralelo.
Aumente o -P 4
para -P 16
ou algo relacionado ao número de CPUs que você possui. A aceleração provavelmente não seria linear, pois cada instância paralela de grep
leria e gravaria no mesmo disco.
Exceto pelo -P
flag para xargs
, todas as coisas nesta resposta devem ser capazes de rodar em qualquer sistema POSIX. O -P
flag para xargs
é não-padrão, mas implementado no GNU xargs
e nos sistemas BSD.