Usando o SO OPEN STEP 4.2 ... No momento, estou usando o seguinte sed
comando:
sed -n '1,/141.299.99.1/p' TESTFILE | tail -3
Este comando encontrará uma instância em um arquivo com o ip 141.299.99.1 e também incluirá 3 linhas antes, o que é bom, exceto que eu também gostaria de encontrar todas as instâncias do IP e as 3 linhas antes dele. e não apenas o primeiro.
Respostas:
Aqui está uma tentativa de emular
grep -B3
usando uma janela móvel sed, com base neste exemplo GNU sed (mas esperamos que seja compatível com POSIX - com reconhecimento a @ StéphaneChazelas):As duas primeiras expressões preparam um buffer de padrão de várias linhas e permitem que ele lide com o caso de borda em que há menos de 3 linhas do contexto anterior antes da primeira correspondência. A expressão do meio (correspondência de expressão regular) imprime uma linha na parte superior da janela até que o texto da correspondência desejada seja exibido no buffer do padrão. A final
$!N;D
rola a janela em uma linha, exceto quando atinge o final da entrada.fonte
-e
não é específico do GNU. Para ser POSIX / portátil, você precisa , pois não pode haver nada depois}
(e você precisa de um;
antes).-e '1h;2,4{H;g;}' -e '1,3d'
? Eu não tenho um sistema não-GNU para testar (e o--posix
comutador GNU sed parece não se importar).sed
baú de ferramentas da herança, que é um descendente do tradicional Unix sed. A especificação POSIX / Unix parased
é a pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.htmlgrep
fará um trabalho melhor disso:Os
-B 3
meios para imprimir as três linhas antes de cada partida. Isso será impresso--
entre cada grupo de linhas. Para desativar isso, use--no-group-separator
também.A
-B
opção também é suportada pelo GNUgrep
e pela maioria das versões do BSD ( OSX , FreeBSD , OpenBSD , NetBSD ), mas tecnicamente não é uma opção padrão.fonte
Com
sed
você pode fazer uma janela deslizante.Isso faz. Mas cuidado -
bash
o comportamento insano de se expandir!
mesmo quando citado !!! na cadeia de comando do seu histórico de comandos pode torná-lo um pouco louco. Prefixe o comando comset +H;
se você achar que este é o caso. Para reativá-lo (mas por que ???), façaset -H
depois.Isso, é claro, só se aplicaria se você estivesse usando
bash
- embora eu não acredite que você esteja. Tenho certeza de que você está trabalhandocsh
- (que é o shell cujo comportamento insanobash
emula a expansão do histórico, mas talvez não nos extremos que o shell c levou) . Então, provavelmente, um\!
deve funcionar. Eu espero.É tudo código portátil: o POSIX descreve seus três operadores assim: (embora valha a pena notar que eu apenas confirmei que essa descrição existia já em 2001)
Portanto, na primeira linha, você adiciona uma linha extra ao espaço do padrão, para que fique assim:
Em seguida, na primeira linha e em todas as linhas posteriores - exceto a última -, você adiciona outra linha ao espaço do padrão. Então fica assim:
Se o seu endereço IP for encontrado dentro de você, você será
P
direcionado para a primeira nova linha, então apenas a linha 1 aqui. No final de cada ciclo, vocêD
elimina o mesmo e recomeça com o que resta. Portanto, o próximo ciclo se parece com:...e assim por diante. Se o seu ip for encontrado em qualquer um desses três, o mais antigo será impresso - sempre. Então você está sempre apenas três linhas à frente.
Aqui está um exemplo rápido. Vou imprimir um buffer de três linhas para cada número que termina em zero:
Isso é um pouco mais complicado do que o seu caso, porque eu tive que alternar entre a
0\n
nova linha ou o0$
fim do espaço do padrão para se parecer mais com o seu problema - mas eles são sutilmente diferentes, pois isso requer uma âncora - o que pode ser um pouco difícil, pois o espaço-padrão muda constantemente.Usei os casos ímpares de 10 e 52 para mostrar que, desde que a âncora seja flexível, o mesmo ocorre com a saída. Totalmente portável, posso obter os mesmos resultados contando com o algoritmo e:
E amplie a pesquisa enquanto restringe minha janela - de 0 a 9 e 0 e de 3 linhas para duas.
Enfim, você entendeu a idéia.
fonte
sed '...' $filename
. A propósito - deixei os períodos da sua própria sequência de pesquisa, mas na verdade não são períodos em um padrão - eles representam qualquer caractere único. Provavelmente, você deve evitáoct\.oct\.oct\.oct
-los para que correspondam apenas a períodos.Como você menciona que não tem a
-B
opçãogrep
, é possível usar o Perl (por exemplo) para fazer uma janela deslizante de 4 linhas:A resposta de Ramesh faz uma coisa semelhante
awk
.fonte
Quando disponível, você pode usar o pcregrep :
fonte
Você pode implementar a mesma abordagem básica que as outras respostas não-grep no próprio shell (isso pressupõe um shell relativamente recente que suporte
=~
):Como alternativa, você pode agrupar o arquivo inteiro em uma matriz:
fonte
Se o seu sistema não suporta
grep
contexto, você pode tentar o ack-grep :ack
é uma ferramenta como grep, otimizada para programadores.fonte
perl
, você pode usarack
.Nisso
awk
solução, é usada uma matriz que sempre conterá 3 linhas antes do padrão atual. Portanto, quando o padrão é correspondido, o conteúdo da matriz, juntamente com o padrão atual, é impresso.Teste
Depois de executar o comando, a saída é,
fonte
Na maioria deles,
/141.299.99.1/
também corresponderá (por exemplo)141a299q99+1
ou141029969951
porque.
em uma expressão regular pode representar qualquer caractere.Usando
/141[.]299[.]99[.]1/
é mais seguro, e você pode adicionar contexto adicional no início e no final de todo o regexp para certificar-se ele não corresponder3141.
,.12
,.104
, etc.fonte