Eu tenho um arquivo que contém linhas como
proto=tcp/http sent=144 rcvd=52 spkt=3
proto=tcp/https sent=145 rcvd=52 spkt=3
proto=udp/dns sent=144 rcvd=52 spkt=3
Eu preciso extrair o valor de proto que é tcp/http
, tcp/https
, udp/dns
.
Até agora eu tentei isso, grep -o 'proto=[^/]*/'
mas apenas capaz de extrair o valor como proto=tcp/
.
sed
,awk
ouperl
nãogrep
.Respostas:
Supondo que isso esteja relacionado à sua pergunta anterior , você está seguindo o caminho errado. Em vez de tentar reunir pedaços de scripts que meio que fazem o que você quer na maioria das vezes e que precisam de um script completamente diferente toda vez que você precisa fazer algo que seja um pouquinho diferente, basta criar um script que possa analisar seu arquivo de entrada em uma matriz (
f[]
abaixo) que mapeia seus nomes de campo (tags) para seus valores e, em seguida, você pode fazer o que quiser com o resultado, por exemplo, considerando esse arquivo de entrada da sua pergunta anterior:podemos escrever um script awk que cria uma matriz dos valores indexados por seus nomes / tags:
e como você pode fazer o que quiser com seus dados, basta referenciá-los pelos nomes dos campos, por exemplo, usando o GNU awk
-e
para facilitar a mistura de um script em um arquivo com um script de linha de comando:fonte
perl
pode ser mais fácil de usar.awk
e complexossed
são mais simplesperl
porque são essencialmente um superconjunto deles, com recursos adicionais para tarefas comuns.s/old/new/g
sed e não seja um awk, então vamos deixar isso de lado. Eu discordo totalmente de que scripts complexos do awk são mais simples em perl. Eles podem ser mais breves, é claro, mas a brevidade não é um atributo desejável do software, a concisão é e é extremamente raro que eles tenham algum benefício real, além de serem geralmente muito mais difíceis de ler, e é por isso que as pessoas postam coisas como zoitz.com / archives / 13 sobre perl e se referem a ele como uma linguagem somente de gravação, diferente do awk. Eu ainda gostaria de ver um perl equivalente a isso, porémCom
grep -o
, você terá que corresponder exatamente ao que deseja extrair. Como você não deseja extrair aproto=
sequência, não deve correspondê-la.Uma expressão regular estendida que corresponderia a uma barra
tcp
ou a ela seriaudp
seguida por uma barra e alguma sequência alfanumérica não vazia éAplicando isso aos seus dados:
Para garantir que apenas façamos isso nas linhas que começam com a sequência
proto=
:Com
sed
, removendo tudo antes do primeiro=
e depois do primeiro caractere em branco:Para garantir que apenas façamos isso nas linhas que começam com a sequência
proto=
, você pode inserir a mesma etapa de pré-processamentogrep
como acima, ou usarAqui, suprimimos a saída padrão com a
-n
opção e, em seguida, acionamos as substituições e uma impressão explícita da linha somente se a linha corresponder^proto=
.Com
awk
, usando o separador de campo padrão e, em seguida, divida o primeiro campo=
e imprima o segundo bit:Para garantir que apenas façamos isso nas linhas que começam com a sequência
proto=
, você pode inserir a mesma etapa de pré-processamentogrep
como acima, ou usarfonte
Se você estiver no GNU grep (para a
-P
opção), poderá usar:Aqui, correspondemos à
proto=
string, para garantir que estamos extraindo a coluna correta, mas a descartamos da saída com o\K
sinalizadorO acima pressupõe que as colunas são separadas por espaço. Se as guias também forem um separador válido, você usaria
\S
para corresponder aos caracteres que não são de espaço em branco; portanto, o comando seria:Se você também deseja se proteger contra os campos de correspondência em que
proto=
há uma substring, como athisisnotaproto=tcp/https
, adicione o limite de palavras da seguinte\b
forma:fonte
grep -oP 'proto=\K\S+'
. Oproto=tcp/http
pode ser seguido por um separador em vez de espaços, e\S
ao contrário[^ ]
irá corresponder a qualquer caractere não-espaço.-o
é um GNUism também.-P
é suportado apenas pelo GNUgrep
se construído com suporte a PCRE (opcional no momento da construção).Usando
awk
:$1 ~ "proto"
garantirá que apenas tomemos medidas de acordo comproto
a primeira colunasub(/proto=/, "")
irá removerproto=
da entradaprint $1
imprime a coluna restantefonte
Código de golfe nas
grep
soluçõesou mesmo
fonte
Usando o
cut
comando:fonte
http
edns
.Apenas outra
grep
solução:E um similar com a
sed
impressão apenas do grupo capturado correspondente:fonte
Outra
awk
abordagem:Isso definirá o separador de campos do awk como um
=
ou um espaço. Então, se a linha corresponder a=
, então,ud
outc
seguida por ump
, imprima o 2º campo a.Outra
sed
abordagem (não é portátil para todas as versões dosed
, mas funciona com o GNUsed
):Os
-n
meios "não imprimir" e-E
permitem expressões regulares estendidas que nos fornecem\S
"espaço em branco",+
"um ou mais" e os parênteses para captura. finalmente, o/p
no final, o sed imprimirá uma linha apenas se a operação for bem-sucedida e, se houver uma correspondência para o operador de substituição.E um perl:
Os
-n
meios "leem o arquivo de entrada linha por linha e aplicam o script fornecido por-e
cada linha". O-l
acrescenta uma nova linha para cadaprint
chamada (e remove novas linhas que saem a partir da entrada). O script em si imprimirá a maior extensão de caracteres que não sejam espaços em branco encontrados após aproto=
.fonte
-E
está ficando cada vez mais portátil, mas\S
não está.[^[:space:]]
é um equivalente mais portátil.Aqui está outra solução bastante fácil:
fonte
grep
não corresponde a nada.[tc,ud]\*\\/.*
procura uma ocorrência det
, ouc
, ou,
ouu
oud
, seguida por um*
caractere literal , depois ap
e uma barra invertida. Você provavelmente quis dizergrep -Eo '(tc|ud)p/.* ' file | awk '{print $1}'
. Mas então, se você estiver usando awk, assim como você pode fazer a coisa toda em awk:awk -F'[= ]' '/(tc|ud)p/{print $2}' file
.[tc,ud]p
significa "um dost
,c
,,
,u
oud
seguido por ump
. Então, ele corresponde aqui apenas porquetcp
temcp
eudp
temdp
. Mas também corresponderia,p
outp
etc Além disso, agora que você tem o*
, ele irá corresponderppp
bem (o*
meios "0 ou mais" para que ele irá corresponder, mesmo quando ele não corresponde) você não quer uma classe de caracteres (.[ ]
), o que você quer é um grupo:(tc|ud)
(uso com a-E
bandeira degrep
.) Além disso, o.*
torna coincidir com a linha inteira.\*
para que o primeiro*
comando aparecesse como um * e não como uma marcação em itálico. Quando você coloca o comando no formato de código, faz com que o\
antes do*
apareça (causando falha no comando). Quando você edita as postagens de outras pessoas, fique atento para alterar a aparência da postagem assim.ppp
. É claro que você está certo de que ele irá corresponder,p
outp
- ouuucp
,ttp
,cutp
,ductp
oud,up
.fonte
opções de corte:
-f
- campo-d
- delímetrofonte