J'ai des fichiers de configuration pré-générés à partir d'un utilitaire. Comment puis-je extraire la chaîne de paramètres délimitée par '), qui peut ou non s'étendre sur plusieurs lignes?

FILE1 peut ressembler à ceci - PARM3 s'étend sur plusieurs lignes:

OPERAND      ID          = 'XXXX',
             ....
             PARM3       = ( 'VALUE3A',
                              ....
                             'VALUE3n'),
             PARM4       = ( 'VALUE4',
                              ....
                             'VALUE4n'),
                              ....

ou FILE2 peut ressembler à ceci - PARM3 ne s'étend pas sur plusieurs lignes:

OPERAND      ID          = 'XXXX',
             ....
             PARM3       = ( 'VALUE3A'),
             PARM4       = ( 'VALUE4',
                              ....
                              'VALUE4n'),
             ....

Pour FILE1, l'extrait est bon si le délimiteur '), est sur une autre ligne:

sed -n "/.* PARM3 .*/,/')\,/p" FILE1

Production:

  PARM3       = ( 'VALUE3A',
                  ....
                  'VALUE3n'),

Pour FILE2, l'extrait ne fonctionne pas si le délimiteur '), se trouve sur la même ligne:

sed -n "/.* PARM3 .*/,/')\,/p" FILE2

Production:

        PARM3       = ( 'VALUE3A'),
        PARM4       = ( 'VALUE4',
                         ....
                        'VALUE4n'),

Comment puis-je corriger cette instruction sed en utilisant sed uniquement pour gérer le délimiteur qui peut ou non être sur la même ligne?

1
et_phonehome 23 mai 2018 à 18:44

3 réponses

Meilleure réponse

[EDIT] plus simple:

sed -n '/PARM3/,/)/{p;/)/q}' file

Une façon avec sed:

sed -n '/PARM3/{:a;/)/{p;q};N;ba}' file

Détails:

/PARM3/ {     # if PARM3 is found
    :a            # define a label "a"
    /)/ {         # if ) is found
        p             # print the pattern space
        q             # quit
    }
    N             # append the next line to the pattern space
    ba            # go to label a
}
1
Casimir et Hippolyte 23 mai 2018 à 16:21

Vous pouvez utiliser cette commande gnu-awk qui utilise un RS personnalisé:

awk -v RS='[[:blank:]]*PARM3[[:blank:]]*=[[:blank:]]*\\([^)]*\\),[[:blank:]]*' 'RT{print RT}' file

Pour file1, cela donne:

     PARM3       = ( 'VALUE3A',
                      ....
                     'VALUE3n'),

Pour file2, cela donne:

    PARM3       = ( 'VALUE3A'),
1
anubhava 23 mai 2018 à 16:22

Si vous avez GNU grep, vous pouvez utiliser son option -z pour traiter l'entrée complète comme une seule ligne:

$ grep -Ezo '\s+PARM3\s+=\s+\([^)]*\)' FILE2

             PARM3       = ( 'VALUE3A',
                              ....
                             'VALUE3n')

-o ne conserve rien d'autre que la correspondance et -E active les expressions régulières étendues.

Le regex recherche PARM3 = entouré d'un nombre arbitraire de blancs, suivi de ( et de tout ce qui va jusqu'à et y compris la fermeture ). Pour éviter les correspondances gourmandes, j'utilise [^)] ("pas une parenthèse fermante").

Si vous n'avez pas besoin des blancs de début, ils peuvent être ignorés, et si vous avez besoin de la virgule de fin, elle peut être ajoutée (facultative, au cas où elle ne serait pas là):

$ grep -Ezo 'PARM3\s+=\s+\([^)]*\),?' infile
PARM3       = ( 'VALUE3A',
                              ....
                             'VALUE3n'),

Ou pour obtenir un alignement correct, mais pas la nouvelle ligne précédant la correspondance:

$ grep -Ezo '[[:blank:]]*PARM3\s+=\s+\([^)]*\),?' infile
             PARM3       = ( 'VALUE3A',
                              ....
                             'VALUE3n'),
0
Benjamin W. 23 mai 2018 à 15:58