Questão grepping uma substring de um resultado grep


Dado um arquivo de log, geralmente faço algo assim:

grep 'marker-1234' filter_log

Qual é a diferença em usar '' ou '' ou nada no padrão?

O comando grep acima irá render muitos milhares de linhas; o que eu desejo. Dentro dessas linhas, geralmente há uma parte dos dados que eu sou depois. Às vezes, eu uso o awk para imprimir os campos que estou procurando. Nesse caso, o formato do log muda, não posso confiar apenas na posição, para não mencionar que os dados reais registrados podem empurrar a posição para frente.

Para tornar isso compreensível, digamos que a linha de registro continha um endereço IP, e era tudo o que eu procurava, para depois canalizá-lo para classificar e exclusivo e obter algumas contagens.

Um exemplo pode ser:

2010-04-08 some logged data, indetermineate chars - [marker-1234] (123.123.123.123) from: foo@bar.example.com to bar@foo.example.com [stat-xyz9876]

O primeiro comando grep me dará muitos milhares de linhas como as acima, a partir daí, eu quero canalizá-lo para alguma coisa, provavelmente sed, que pode extrair um padrão e imprimir apenas o padrão.

Para este exemplo, usar o endereço IP seria suficiente. Eu tentei. É sed não é capaz de entender [0-9] {1,3}. como um padrão? Eu tive que [0-9] [0-9] [0-9]. que produziu resultados estranhos até todo o padrão criado.

Isso não é específico para um endereço IP, o padrão será alterado, mas posso usá-lo como um modelo de aprendizado.

Obrigado a todos.


4


origem


Isso soa muito relacionado à programação, até mesmo simples comandos bash como grep e awk são, na minha opinião, melhor respondidas no stackoverflow. - Josh K
@Josh: SU tem muitos guerreiros de linha de comando do Linux que podem lidar com esse tipo de pergunta, e é bem-vindo aqui. pode ser uma daquelas perguntas que caberiam em qualquer um dos sites, então cabe ao que perguntou. - quack quixote
Pensei um pouco e, para ser sincero, não sabia onde postá-lo. Eu fui com o nome dos sites, imaginando que SO é mais geral, e SU é mais coisa do tipo admin. Acho que o shell script mais rápido é relacionado ao administrador. Claro, você entra em grandes projetos exclusivos tcl ou bash por um motivo ou outro, e nesse caso eu os restringiria a programação relacionada e postaria em SO. Este era mais um forro e SU parecia um bom lar. Desculpe se eu postei no lugar errado, mas parece uma área cinzenta em alguns casos. - user17245
@allentown: na verdade, o Server Fault é mais coisa do tipo admin; Super User é mais coisa do usuário final. (mas usuários finais usuários avançados.) de qualquer forma, essa questão é provavelmente bem-vinda em qualquer SO / SF / SU. você já aceitou uma resposta, por isso, se estiver satisfeito, pode terminar. ou se você quiser, podemos migrá-lo para SO / SF; apenas sinalize para a atenção do moderador e diga-nos onde enviá-lo. obrigado! - quack quixote
@quack: Tudo bem, eu estava pensando que uma resposta melhor poderia ser encontrada lá, no entanto, parece que já foi encontrada. - Josh K


Respostas:


Eu não sei em qual SO você está, mas no FreeBSD 7.0+ o grep tem um -o opção para retornar apenas a parte que corresponde ao padrão. Então você poderia
grep "marker-1234" filter_log | grep -oE "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"

Retorna uma lista de apenas endereços IP do 'filter_log' ...

Isso funciona no meu sistema, mas, novamente, eu não sei o que sua versão do grep suporta.


7



Acho que todas as respostas aqui são excelentes maneiras de aprender e abordar o resultado final com a mesma resposta. Eu particularmente gosto deste como é facilmente lembrável e é apenas encadeamento de vários comandos grep. No Mac OS X, parece que tenho a opção -o e, claro, uso a opção -E já com bastante frequência. Obrigado por sua resposta - user17245


você pode fazer tudo isso em apenas um awk comando. Não há necessidade de usar outras ferramentas

$ awk '/marker-1234/{for(o=1;o<=NF;o++){if($o~/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/)print $o }  }' file
(123.123.123.123)

3



Obrigado, isso funciona, awk pode machucar sua cabeça um pouco às vezes, mas eu estou me acostumando com o FOO .... um aspecto de linha de coisas rápidas no shell. Muito poderoso. - user17245


Você pode encurtar o segundo grep um pouco assim:

grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}'

Para responder à sua primeira pergunta, as aspas duplas permitem que o shell faça várias coisas, como expansão de variáveis, mas proteja alguns metacaracteres da necessidade de serem escapados. As aspas simples impedem que o shell faça essas expansões. Não usar citações deixa as coisas abertas.

$ empty=""
$ text1="some words"
$ grep $empty some_file
(It seems to hang, but it's just waiting for input since it thinks "some_file" is 
the pattern and no filename was entered, so it thinks input is supposed to come
from standard input. Press Ctrl-d to end it.)
$ grep "$empty" some_file
(The whole file is shown since a null pattern matches everything.)
$ grep $text1 some_file
grep: words: No such file or directory
some_file:something
some_file:some words
(It sees the contents of the variable as two words, the first is seen as the 
pattern, the second as one file and the filename as a second file.)
$ grep "$text1" some_file
some_file:some words
(Expected results.)
$ grep '$text1' some_file
(No results. The variable isn't expanded and the file doesn't contain a
string that consists of literally those characters (a dollar sign followed
by "text1"))

Você pode aprender mais na seção "QUOTING" do man bash


2



Ótimo escrever, obrigado. Eu preciso lidar melhor com isso com o regad para o IFS, bem, eu estava bem ligado a isso no outro dia, mas consegui fazer o IFS jogar bem. É uma coisa terrível quando você tem IFS definido e esqueceu sobre isso, pergunto-me wtf está acontecendo por uma hora. - user17245
É uma boa ideia ter o hábito de sempre salvar o valor de IFS e restaure o mais rápido possível: saveIFS="$IFS"; IFS=","; do_something; IFS="$saveIFS"; do_other_stuff - Dennis Williamson
+ 1 boa chamada no regex, eu não uso muito, então eu costumo ser um pouco ineficiente. - Chris S


Olhe para cima xargs comando. Você deveria ser capaz de fazer algo como:

grep 'marker-1234' filter_log | xargs grep "(" | cortar -c1-15

Isso pode não ser exatamente, mas xargs é o comando que você deseja usar


1