1
votes

Comment extraire du texte suivant un mot-clé sous UNIX

J'ai un fichier texte ( file.txt ) qui contient un mur de résultats (pas de sauts de ligne, d'espaces, etc.) que j'ai reçu d'une source externe. À partir de ce fichier, je dois trouver toutes les mentions du mot serId , puis imprimer la séquence alphanumérique qui le suit. La séquence alphanumérique est de n'importe quelle longueur mais se terminera par le caractère , . Comment puis-je extraire ces séquences alphanumériques?

J'ai essayé de trouver des scripts / code en utilisant sed / awk mais les résultats semblent tourner autour d'une séquence connue à trouver, plutôt que d'une séquence inconnue.

Par exemple, je voudrais extraire 28655784-EE de l'exemple de texte suivant:

{"preRollbackCheckResults":[],"patchingHistory":[{"backupStatus":"Available","rollbackStatus":"Available","additionalNote":"Patching CDS as planned","appliedBy":"xxrbsgCDS02services","appliedDate":"2019-01-18T12:45:33.926+0000","totalTime":"29 min, 47 sec","serId":"28655784-EE","patchDescription":"DB 18.4.0.0.0 Oct 2018 PSU


4 commentaires

fournir un exemple de fichier d'entrée. pour une séquence inconnue, vous utilisez la correspondance RegEx. ask est l'outil.


J'utilise grep 2.20 et il semble prendre en charge l'option -o. Et un exemple du fichier .txt serait t {"preRollbackCheckResults": [], "patchingHistory": [{"backupSta‌ tus": "Available", "ro‌ llbackStatus": "Disponible", "additionalNot‌ e ":" Correctif CDS comme prévu "," applyBy ":" xxrbsgCDS02services "," appliedDate ":" 20‌ 19-01-18T12: 45: 33.92‌ 6 + 0000 "," totalTime ": ‌" 29 min , 47 sec "," serId ":" 28655784-EE "," patchDescription ":" DB 18.4.0.0.0 oct 2018 PSU ... Donc ce que j'essaierais de faire est de trouver "serId" dans le fichier puis d'extraire "28655784-EE", qui le suit.


Je ne suis pas sûr mais cela ressemble à un fichier json , avez-vous regardé jq ?


modifiez votre question pour afficher un exemple d'entrée concis et testable et la sortie attendue afin que nous puissions vous aider. La bonne solution n'est PAS de combiner grep + awk comme vous semblez vous en diriger dans vos commentaires sous les réponses actuelles de grep et awk.


4 Réponses :


2
votes

Essayez ce script awk (gawk uniquement):

awk  -F '","' 'match($0,/serId\":\"[^,]*/,m){print m[1]","}' input.txt

Si vous avez besoin du ,

awk  -F '","' 'match($0,/serId\":\"[^,]*/,m){print m[1]}' input.txt

explication:

-F "," analyse le fichier en enregistrements séparés par ,

match ($ 0 , "serId [^,] *", m) filtre dans l'enregistrement courant, correspondant à une chaîne commençant par serId se terminant par , . Mettre le résultat dans le tableau m

print substr (m [0], 8) imprimer la chaîne correspondante à partir de la 8ème position

p >


6 commentaires

Cela a fonctionné lorsque j'ai combiné votre solution avec celle de Dominique. Merci beaucoup.


Je l'ai fait mais le vote positif ne persistera pas. Je ne sais pas pourquoi?


Ah. "Les votes exprimés par ceux qui ont moins de 15 points de réputation sont enregistrés, mais ne modifient pas le score affiché publiquement." Mais j'ai voté pour.


Le deuxième argument de match () est une expression rationnelle, pas une chaîne, vous devez donc utiliser l'expression régulière / au lieu des délimiteurs de chaîne ", c'est-à-dire match ($ 0, / serId ":" [^,] * /, ..) au lieu de match ($ 0, "serId \": \ "[^,] *", ..) . [^,] * devrait vraiment être [^ "] * cependant et tout l'intérêt d'utiliser gawk pour le 3e argument à match () est d'isoler les segments de l'expression rationnelle capturez les groupes à référencer dans le bloc d'action afin que le code soit vraiment match ($ 0, / serId ":" ([^ "] *) /, m) {print m [1]} sinon avec n'importe quel awk que vous pouvez écrire match ($ 0, / serId ":" [^ "] * /) {print substr ($ 0, RSTART + 8, RLENGTH-8)}


Merci à @Ed Morton, mis à jour avec les recommandations.


De rien. Vous avez cependant besoin des parenthèses pour créer le groupe de capture et vous n'avez pas besoin d'échapper les guillemets doubles à l'intérieur des / s donc utilisez / serId ":" ([^ "] *) / pas / serId \ ": \" [^,] * /



1
votes

grep -o est une solution très simple pour cela:

J'ai créé un fichier, contenant les lignes suivantes:

serIdABCde123;

La première ligne ne se termine pas par un point-virgule, la troisième ligne commence par le mauvais mot, donc seule la deuxième ligne est correcte.

J'ai lancé la commande suivante: grep -o " serId [0-9a-zA-Z] *; " testtttt.txt , avec le résultat suivant:

serId12345
serIdABCde123;
Ser_idblabla;


1 commentaires

Cela a fonctionné lorsque j'ai combiné votre solution avec celle de Dudi Boy. Merci beaucoup.



0
votes

Sur la base du court exemple que vous avez publié dans un commentaire, j'ai deux suggestions:

  • Si le fichier est un json a>, essayez de comprendre sa structure et utilisez jq .

  • S'il est mal formé et ne peut être interprété que comme un tas de texte, utilisez le Perl suivant:

    $ cat file.txt
    {"preRollbackCheckResults":[],"patchingHistory":[{"backupStatus":"Available","rollbackStatus":"Available","additionalNote":"Patching CDS as planned","appliedBy":"xxrbsgCDS02services","appliedDate":"2019-01-18T12:45:33.926+0000","totalTime":"29 min, 47 sec","serId":"28655784-EE","patchDescription":"DB 18.4.0.0.0 Oct 2018 PSU{"preRollbackCheckResults":[],"patchingHistory":[{"backupStatus":"Available","rollbackStatus":"Available","additionalNote":"Patching CDS as planned","appliedBy":"xxrbsgCDS02services","appliedDate":"2019-01-18T12:45:33.926+0000","totalTime":"29 min, 47 sec","serId":"28655784-EE","patchDescription":"DB 18.4.0.0.0 Oct 2018 PSU
    
    $ perl -lne '@m=/"serId":"([^"]+)"/g; print "@m"' file.txt
    28655784-EE 28655784-EE
    

    Exécution de test:

    perl -lne '@m=/"serId":"([^"]+)"/g; print "@m"' file.txt
    


0 commentaires

0
votes

Avec n'importe quel sed:

$ sed 's/.*"serId":"\([^"]*\).*/\1/' file
28655784-EE


0 commentaires