J'ai un fichier qui contient des lignes comme
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
Je dois extraire la valeur de proto qui est tcp/http
, tcp/https
, udp/dns
.
Jusqu'à présent, j'ai essayé cela, grep -o 'proto=[^/]*/'
mais je n'ai pu extraire la valeur que proto=tcp/
.
sed
,awk
ouperl
nongrep
.Réponses:
En supposant que cela est lié à votre question précédente , vous vous trompez de chemin. Plutôt que d'essayer de reconstituer des morceaux de scripts qui feront un peu / sorta ce que vous voulez la plupart du temps et ayant besoin d'obtenir un script complètement différent à chaque fois que vous avez besoin de faire quelque chose de légèrement différent, créez simplement 1 script qui peut analyser votre fichier d'entrée dans un tableau (
f[]
ci-dessous) qui mappe les noms de vos champs (balises) à leurs valeurs, puis vous pouvez faire tout ce que vous voulez avec le résultat, par exemple, étant donné ce fichier d'entrée de votre question précédente:nous pouvons écrire un script awk qui crée un tableau des valeurs indexées par leurs noms / balises:
et étant donné que vous pouvez faire ce que vous voulez avec vos données, il suffit de les référencer par les noms de champs, par exemple en utilisant GNU awk
-e
pour faciliter le mélange d'un script dans un fichier avec un script de ligne de commande:la source
perl
peut être plus facile à utiliser.awk
etsed
scripts sont généralement plus simplesperl
car il s'agit essentiellement d'un surensemble d'entre eux, avec des fonctionnalités supplémentaires pour les tâches courantes.s/old/new/g
sed et sed n'est pas génial donc laisse cela de côté. Je ne suis absolument pas d'accord pour dire que les scripts awk complexes sont plus simples en perl. Ils peuvent être plus brefs bien sûr, mais la brièveté n'est pas un attribut souhaitable du logiciel, la concision est, et il est extrêmement rare pour eux d'avoir un réel avantage et ils sont généralement beaucoup plus difficiles à lire, c'est pourquoi les gens publient des choses comme zoitz.com / archives / 13 sur perl et y faire référence comme un langage en écriture seule, contrairement à awk. J'aimerais quand même voir un équivalent perl à celaAvec
grep -o
, vous devrez faire correspondre exactement ce que vous voulez extraire. Puisque vous ne voulez pas extraire laproto=
chaîne, vous ne devez pas la faire correspondre.Une expression régulière étendue qui correspondrait
tcp
ou seraitudp
suivie d'une barre oblique et d'une chaîne alphanumérique non vide estAppliquer cela sur vos données:
Pour vous assurer que nous ne le faisons que sur les lignes commençant par la chaîne
proto=
:Avec
sed
, tout supprimer avant le premier=
et après le premier caractère vierge:Pour vous assurer que nous ne le faisons que sur les lignes commençant par la chaîne
proto=
, vous pouvez insérer la même étape de prétraitementgrep
que ci-dessus, ou vous pouvez utiliserIci, nous supprimons la sortie par défaut avec l'
-n
option, puis nous déclenchons les substitutions et une impression explicite de la ligne uniquement si la ligne correspond^proto=
.Avec
awk
, en utilisant le séparateur de champs par défaut, puis en divisant le premier champ=
et en imprimant le deuxième bit:Pour vous assurer que nous ne le faisons que sur les lignes commençant par la chaîne
proto=
, vous pouvez insérer la même étape de prétraitementgrep
que ci-dessus, ou vous pouvez utiliserla source
Si vous êtes sur GNU grep (pour l'
-P
option), vous pouvez utiliser:Ici, nous faisons correspondre la
proto=
chaîne, pour nous assurer que nous extrayons la colonne correcte, mais nous la supprimons de la sortie avec l'\K
indicateur.Ce qui précède suppose que les colonnes sont séparées par des espaces. Si les tabulations sont également un séparateur valide, vous utiliseriez
\S
pour faire correspondre les caractères non blancs, donc la commande serait:Si vous souhaitez également vous protéger contre les champs de correspondance où se
proto=
trouve une sous-chaîne, comme unthisisnotaproto=tcp/https
, vous pouvez ajouter une limite de mot avec\b
ceci:la source
grep -oP 'proto=\K\S+'
. Leproto=tcp/http
peut être suivi d'un onglet au lieu d'espaces et,\S
contrairement à[^ ]
, correspondra à tout caractère non espace.-o
c'est aussi un GNUisme.-P
n'est pris en charge par GNU quegrep
s'il est construit avec le support PCRE (facultatif au moment de la construction).En utilisant
awk
:$1 ~ "proto"
assurera que nous n'agissons que sur les lignes avecproto
dans la première colonnesub(/proto=/, "")
va supprimerproto=
de l'entréeprint $1
imprime la colonne restantela source
Code golf sur les
grep
solutionsou même
la source
Utilisation de la
cut
commande:la source
http
etdns
.Juste une autre
grep
solution:Et un modèle similaire avec
sed
impression uniquement du groupe capturé correspondant:la source
Une autre
awk
approche:Cela définira le séparateur de champ awk sur l'un
=
ou sur un espace. Ensuite, si la ligne correspond à a=
, alors soitud
outc
suivi de ap
, imprimez le 2ème champ.Une autre
sed
approche (non portable sur toutes les versions desed
, mais fonctionne avec GNUsed
):Le
-n
moyen "ne pas imprimer" et le-E
permet des expressions régulières étendues qui nous donnent\S
pour "non-blanc",+
pour "un ou plusieurs" et les parenthèses pour la capture. Enfin,/p
à la fin fera sed imprimer une ligne uniquement si l'opération a réussi donc s'il y avait une correspondance pour l'opérateur de substitution.Et, un perl:
Le
-n
moyen "lit le fichier d'entrée ligne par ligne et applique le script donné par-e
à chaque ligne". Le-l
ajoute une nouvelle ligne à chaqueprint
appel (et supprime les nouvelles lignes sortantes de l'entrée). Le script lui-même imprimera la plus longue séquence de caractères non blancs trouvée après aproto=
.la source
-E
devient de plus en plus portable, mais\S
ne l'est pas.[^[:space:]]
est un équivalent plus portable.Voici une autre solution assez simple:
la source
grep
ne correspond à rien.[tc,ud]\*\\/.*
recherche une occurrence det
, ouc
, ou,
ouu
oud
, suivie d'un*
caractère littéral , puis de ap
et d'une barre oblique inverse. Vous vouliez probablement diregrep -Eo '(tc|ud)p/.* ' file | awk '{print $1}'
. Mais alors, si vous utilisez awk, vous pouvez aussi bien faire la chose en awk:awk -F'[= ]' '/(tc|ud)p/{print $2}' file
.[tc,ud]p
signifie « l' un dest
,c
,,
,u
oud
suivi d'unp
. Il correspond ici seulement parce quetcp
acp
etudp
adp
. Mais il serait également correspondre,p
outp
etc., maintenant que vous avez également le*
, il correspondrappp
aussi bien (la des*
moyens « 0 ou plus » il correspondra même quand il ne correspond pas) vous ne voulez pas une classe de caractères (.[ ]
), ce que vous voulez est un groupe:(tc|ud)
(utiliser avec le-E
drapeaugrep
.) en outre, le.*
rend correspondre à toute la ligne\*
pour que le premier*
de leur commande apparaisse sous la forme d'un * et non en italique. Lorsque vous mettez la commande au format de code, vous avez fait apparaître\
avant le*
(provoquant ainsi l'échec de la commande). Lorsque vous modifiez les publications d'autres personnes, faites attention à ne pas modifier l'apparence de la publication comme ceci.ppp
. Bien sûr , vous avez raison qu'il corresponde,p
outp
- ouuucp
,ttp
,cutp
,ductp
oud,up
.la source
options de coupe:
-f
- champ-d
- délimètrela source