Comment faire correspondre la chaîne exacte en utilisant `sed`? Mais pas la partie de celui-ci.?

8

J'ai un fichier d'entrée FILE1.TXT comme ci-dessous.


11 id1  
12  
13 AGE = 20  
14 NAME = NAME1  
15  
16 id2  
17  
18 AGE = 30  
19 NAME = NAME2  
.  
.  
.  
110 idXYZ  
111  
112 AGE = AGEXYZ  
113 NAME = NAMEXYZ  
114  
115 idZZZ  
116

Je souhaite rechercher tous les champs qui appartiennent à un identifiant particulier et obtenir la valeur de NAME

J'ai réussi à parcourir chaque identifiant et à former la commande ci-dessous pour chaque identifiant selon les besoins.

sed -n '/11/,/14/p' FILE1.TXT | grep NAME | awk -F "= " '{print $2}'

Le problème ici est que j'obtiens la sortie NAME1 , en plus de cela, j'obtiens également NAMEXYZ .

Que faut-il changer pour ne recevoir que NAME1 mais pas NAMEXYZ ?

Comme solution de contournement, les commandes ci-dessous fonctionnent.

sed -n '/11/,/14/p' FILE1.TXT | grep NAME | awk -F "= " '{print $2}'|head -1

Y a-t-il un «commutateur» ou est-ce que je manque quelque chose?

Vinay
la source

Réponses:

3

Si vous connaissez les numéros de ligne que vous souhaitez rechercher (comme le suggère votre Q), resserrez l'expression régulière afin de ne pas faire correspondre les lignes indésirables.

Par exemple, changez:

sed -n '/11/,/14/p' | grep NAME | awk -F "= " '{print $2}'

à

sed -n '/^11 /,/^14 /p' | grep NAME | awk -F "= " '{print $2}'

Le ^correspondra au début de la ligne et un espace après le numéro garantit que le numéro de ligne spécifique sera mis en correspondance, et vous ne traiterez pas les blocs indésirables.

casey
la source
Cela aiderait. Mais, comment puis-je faire correspondre ^(random no of spaces)11?
Vinay
1
@VinayChalluru usesed -n '/^\s*11 /,/^\s*14 /p'
casey
1
cela peut être court en utilisant sed -n '/^11 /,/^14 /p' | awk '/NAME/{print $NF}' avez-vous essayé cela?
Rahul Patil
@RahulPatil Oui, cela fonctionne.
Vinay
6

Utilisez les limites des mots:

grep '\bNAME1\b'

correspondrait NAME1et non NAME1XYZou XYZNAME1.

De même,

sed -n '/11\b/,/14\b/p'

ne correspondrait pas aux lignes contenant 111et 142.


EDIT: Il semble que les numéros du fichier d'entrée soient en fait des numéros de ligne. Si tel est le cas, vous pouvez simplement dire:

sed '11,14!d'

pour obtenir les lignes souhaitées.

devnull
la source
Il n'y en a qu'un NAMEentre les lignes 11 et 14. Alors, pourquoi sedregarde 111- 114t-on et ? Comment faire pour qu'il ne regarde pas entre 111et 114?
Vinay
@VinayChalluru Voir la réponse ci-dessus pour savoir comment modifier l' sedexpression.
devnull
Cela répond à ma question, je suppose. Laissez-moi essayer de vous le faire savoir.
Vinay
pour les limites de mots, grepavec -windicateur? n'est-ce pas?
Rahul Patil
1
@RahulPatil Yup, pour l'exemple ci-dessus -wserait équivalent. Pour l' sedexemple, -west légèrement différent.
devnull
4

Vous pouvez utiliser AWK

awk 'NR>=13 && NR<=17 && /NAME/{print $NF}' infile

Cela recherchera les lignes entre 13 et 17 puis recherchera le nom et s'il correspond, il imprimera le dernier mot de Name = LastWord

Rahul Patil
la source
Lorsque j'essaie de le faire, j'obtiens une erreur indiquant que le numéro de ligne d'entrée doit être inférieur à 199.
Vinay
@VinayChalluru pouvez-vous me montrer la sortie avec la commande, utilisez paste.ubuntu.com
Rahul Patil
Mes excuses. J'ai ajouté un $avant NRet cela a causé l'erreur.
Vinay
@VinayChalluru C'est OK. c'est bien vous avez essayé / testé chaque année et appris quelque chose de nouveau ..: D
Rahul Patil
Exactement. Il reste encore beaucoup à faire. :-)
Vinay
4

Vous n'avez besoin d'aucun autre outil pour cela, vous sedpourrez facilement le gérer en entier.

sed -nr '/11/,/14/{s/^.*NAME =\s*(\S*).*$/\1/p}' <$infile

Cela ne devrait vous fournir que la première séquence de caractères non blancs suivant la phrase "NAME =" pour chaque ligne sur laquelle cette phrase se trouve entre les lignes 11 et 14 de tout fichier d'entrée sedest alimenté.

mikeserv
la source
3

sed n'est pas le bon outil pour ce travail. Utilisez awk où vous pouvez spécifier l'ID que vous recherchez et imprimer le prochain NOM qui apparaît.

awk -v id="id2" '
    $NF == id {have_id = 1} 
    have_id && $0 ~ /NAME/ {print $NF; exit}
' filename
glenn jackman
la source
Pourriez-vous expliquer les lignes deux et trois de votre commande awk?
erik
0

version générique non basée sur le numéro de ligne mais la référence de l'id

sed -n '1h;1!H;
$ {
  x
  s/.*/&\^J/
: clean
#  put your ID pattern here in place of id9
  s/.*\(id9 *\n.*\)id[0-9]\{1,\} *\n.*/\1/
  t clean
  s/.*NAME = \([^[:cntrl:]]*\)\n.*/\1/
  p
  }' YourFile
  1. charger tout le fichier
  2. section propre ne faisant pas partie du groupe id (récursif)
  3. il suffit de prendre la valeur de contenu NAME dans le groupe
  4. imprimer le résultat
NeronLeVelu
la source
0

vous pouvez imprimer les lignes qui contiennent le motif correspondant en utilisant sed comme suit:

sed -n '/pattern/p'  Filename
  • -n- ces options désactivent cette impression automatique, et sed ne produit de sortie que lorsque cela est explicitement demandé via la pcommande.

  • p - impression

user182845
la source