Forum Programmation.shell Awk : Besoin d'explications

Posté par . Licence CC by-sa
Tags : aucun
0
30
août
2017

Salut à tous,

J'aurais besoin d'explications pour comprendre une commande que j'ai trouvée ici.

Je ne comprends pas la partie

{f=NR} f&&NR-1==f RS="1"

Comment && puis == fonctionnent ensemble dans cette commande ? etc… J'ai bien saisi le but (RS utilise le caractère "1" comme séparateur et on affiche l'item après notre pattern en incrémentant NR) mais pas le fonctionnement.

Merci pour votre aide.

  • # grymoire

    Posté par . Évalué à 4 (+2/-0).

    Ce site est juste génial pour comprendre les outils UNIX quand on les découvre.
    Je t'avoue ne pas maîtriser awk, mais je pense qu'en passant un peu de temps à lire la bonne section, tu devrais comprendre ce bout de code.

  • # Une explication

    Posté par . Évalué à 10 (+9/-0).

    Bonjour,

    La commande complète et ce qui est attendu:

    $ echo FIELDA01VALUEA01FIELDA21VALUEA21FIELDA31VALUEA3 |awk -F1 '/FIELDA2/{f=NR} f&&NR-1==f' RS="1"
    FIELDA2
    

    Pour comprendre comment ça marche, le plus simple, ici, est de l'exécuter morceau par morceau en affichant les valeurs des variables:

    • Dans un premier temps, le RS="1" est vrai tout au long du programme. Le caractère "1" remplace le retour à la ligne (\n) pour séparer les Records (une ligne en temps normal).
    $ echo FIELDA01VALUEA01FIELDA21VALUEA21FIELDA31VALUEA3 |awk '{print}' RS="1"
    FIELDA0
    VALUEA0
    FIELDA2
    VALUEA2
    FIELDA3
    VALUEA3
    
    • Ensuite, chaque expression est constituée d'un motif (Pattern) et d'une action. Nous en avons 2:
    Motif n°1: /FIELDA2/      Action n°1: {f=NR} 
    Motif n°2: f&&NR-1==f     Action n°2: Absente, donc {print}
    
    • Le motif n°1 est une expression régulière qui sera vraie si la ligne contient "FIELDA2". Dans ce cas, l'action assignera le numéro de ligne courant NR à f.
    $ echo FIELDA01VALUEA01FIELDA21VALUEA21FIELDA31VALUEA3 |awk '/FIELDA2/{f=NR} ; END{print f}'
    5
    
    • Comme f contient le numéro de ligne de la clef recherchée, reste à afficher la ligne suivante qui contient la valeur. Elle est sélectionnée par f&&NR-1==f qui s'écrit f && ( (NR-1) == f). Considérons seulement (NR-1)==f, cette expression est vraie 2 fois, une avant l'assignation de la première expression, l'autre après.
    $ echo FIELDA01VALUEA01FIELD31VALUE31FIELDA21VALUEA21FIELDA31VALUEA3 |awk '/FIELDA2/{f=NR} ; (NR-1==f){print NR, f, $0}' RS="1"
    1  FIELDA0
    6 5 VALUEA2
    

    Donc on se protège en vérifiant que f est assigné: ( ( f ) && ( ( NR -1 ) == f ) )

    On peut donc écrire le programme comme

    BEGIN{ RS="1" ; f="" ; }
    /FIELDA2/{ f=NR ; }
    (f && ( ( NR -1 ) == f) ) { print; }
    

    Note: Le séparateur "1" n'est pas très bien choisi (pas de FIELDA1)

    • [^] # Re: Une explication

      Posté par . Évalué à 1 (+0/-0). Dernière modification le 30/08/17 à 22:46.

      Ok je vois. Donc au final on n'incrémente pas NR, on attend qu'il prend une valeur supérieure de 1 à f, qui lui même n'aura une valeur que lorsque l'on trouvera le pattern FIELDA2, puis le ET logique && permet d'être sûr qu'on affichera $0 uniquement quand f existe. C'est vraiment ingénieux…

      Tes explications étaient super claires pma. Un grand merci.

    • [^] # Re: Une explication

      Posté par (page perso) . Évalué à 1 (+1/-1).

      Non pas tout à fait d'accord sur ce qui est attendu :

      echo FIELDA01VALUEA01FIELDA21VALUEA21FIELDA31VALUEA3 |awk -F1 '/FIELDA2/{f=NR} f&&NR-1==f' RS="1"
      VALUEA2
      

      et pas FIELDA2.

      En dehors de cela, c'est parfaitement clair. Merci.

Envoyer un commentaire

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.