Comment puis-je écrire un script sed sur les informations de grep à partir d’un fichier texte

J’essaie de faire mes devoirs qui se limitent à utiliser uniquement sed pour filtrer un fichier d’entrée à un certain format de sortie. Voici le fichier d’entrée ( stocks nommés):

 Symbol;Name;Volume ================================================ BAC;Bank of America Corporation Com;238,059,612 CSCO;Cisco Systems, Inc.;28,159,455 INTC;Intel Corporation;22,501,784 MSFT;Microsoft Corporation;23,363,118 VZ;Verizon Communications Inc. Com;5,744,385 KO;Coca-Cola Company (The) Common;3,752,569 MMM;3M Company Common Stock;1,660,453 ================================================ 

Et le résultat doit être:

 BAC, CSCO, INTC, MSFT, VZ, KO, MMM 

J’ai trouvé une solution, mais ce n’est pas efficace. Voici mon script sed (nommé try.sed ):

 /.*;.*;[0-9].*/ { N N N N N N s/\(.*\);.*;.*\n\(.*\);.*;.*\n\(.*\);.*;.*\n\(.*\);.*;.*\n\(.*\);.*;.*\n\(.*\);.*;.*\n\(.*\);.*;.*/\1, \2, \3, \4, \5, \6, \7/gp } 

La commande que je lance sur le shell est la suivante:

 $ sed -nf try.sed stocks 

Ma question est la suivante: existe-t-il une meilleure façon d’utiliser sed pour obtenir le même résultat? Le script que j’ai écrit ne fonctionne qu’avec 7 lignes de données. Si les données sont plus longues, je dois modifier à nouveau mon script. Je ne sais pas comment je peux améliorer les choses, alors je demande ici de l’aide!

Merci pour toutes les recommandations.

    Une autre façon d’utiliser sed :

     sed -ne '/^====/,/^====/ { /;/ { s/;.*$// ; H } }; $ { g ; s/\n// ; s/\n/, /g ; p }' stocks 

    Sortie:

     BAC, CSCO, INTC, MSFT, VZ, KO, MMM 

    Explication:

     -ne # Process each input line without printing and execute next commands... /^====/,/^====/ # For all lines between these... { /;/ # If line has a semicolon... { s/;.*$// # Remove characters from first semicolon until end of line. H # Append content to 'hold space'. } }; $ # In last input line... { g # Copy content of 'hold space' to 'pattern space' to work with it. s/\n// # Remove first newline character. s/\n/, /g # substitute the rest with output separator, comma in this case. p # Print to output. 

    Edit: J’ai édité mon algorithme, car j’avais négligé de prendre en compte l’en-tête et le pied de page (je pensais qu’ils étaient juste pour notre bénéfice).

    sed , de par sa conception, accède à chaque ligne d’un fichier d’entrée, puis exécute des expressions sur celles qui correspondent à certaines spécifications (ou aucune). Si vous adaptez votre script à un certain nombre de lignes, vous faites certainement quelque chose de mal! Je ne vous écrirai pas de script car il s’agit d’un devoir, mais l’idée générale d’une méthode consiste à écrire un script qui effectue les opérations suivantes. Considérez la commande comme l’ordre dans lequel les choses doivent se trouver dans un script.

    1. Ignorez les trois premières lignes en utilisant d , ce qui supprime l’espace du motif et passe immédiatement à la ligne suivante.
    2. Pour chaque ligne qui n’est pas une ligne vide, procédez comme suit. (Tout cela se trouverait dans un seul ensemble d’accolades.)
      1. Remplacez tout après le premier point-virgule ( ; ) par une virgule et un espace (“,”) à l’aide de la commande s (substitut).
      2. Ajouter l’espace de modèle actuel dans le tampon de mise en attente (voir H ).
      3. Supprimez l’espace du motif et passez à la ligne suivante, comme à l’étape 1.
    3. Pour chaque ligne qui parvient à ce point dans le script (doit être la première ligne vide), récupérez le contenu de l’espace de conservation dans l’espace du modèle. (Ce serait après les accolades ci-dessus.)
    4. Remplacez toutes les nouvelles lignes dans l’espace du motif par rien.
    5. Ensuite, remplacez la dernière virgule et espace dans l’espace du motif par rien.
    6. Enfin, quittez le programme pour ne plus traiter de lignes. Mon script a fonctionné sans cela, mais je ne suis pas sûr à 100% pourquoi.

    Cela étant dit, ce n’est qu’une façon de procéder. sed offre souvent différents moyens de complexité variable pour accomplir une tâche. Une solution que j’ai écrite avec cette méthode comporte 10 lignes.

    En tant que note, je ne dérange pas la suppression de l’impression (avec -n ) ou l’impression manuelle (avec p ); chaque ligne est imprimée par défaut. Mon script fonctionne comme ceci:

     $ sed -f companies.sed companies BAC, CSCO, INTC, MSFT, VZ, KO, MMM 

    Cette commande sed devrait produire la sortie requirejse:

     sed -rn '/[0-9]+$/{s/^([^;]*).*$/\1/p;}' file.txt 

    OU sur Mac:

     sed -En '/[0-9]+$/{s/^([^;]*).*$/\1/p;}' file.txt 

    Cela pourrait fonctionner pour vous:

     sed '1d;/;/{s/;.*//;H};${g;s/.//;s/\n/, /g;q};d' stocks 
    • Nous ne voulons pas les titres, alors supprimons-les. 1d
    • Tous les éléments de données sont délimités par ; alors concentrons-nous sur ces lignes. /;/
    • Parmi les choses ci-dessus, supprimez tout du premier ; à la fin de la ligne et ensuite le ranger dans l’espace d’attente (HS) {s/;.*//;H}
    • Lorsque vous arrivez à la dernière ligne, remplacez-la par la commande SH à l’aide de la commande g , supprimez la première ligne (générée par la commande H ), remplacez toutes les nouvelles lignes par une virgule et un espace et imprimez ce qui rest. ${g;s/.//;s/\n/, /g;q}
    • Supprimer tout le rest d

    Voici une session de terminal montrant l’affinement incrémentiel de la construction d’une commande sed:

     cat <stock # paste the file into a here doc and pass it on to a file > Symbol;Name;Volume > ================================================ > > BAC;Bank of America Corporation Com;238,059,612 > CSCO;Cisco Systems, Inc.;28,159,455 > INTC;Intel Corporation;22,501,784 > MSFT;Microsoft Corporation;23,363,118 > VZ;Verizon Communications Inc. Com;5,744,385 > KO;Coca-Cola Company (The) Common;3,752,569 > MMM;3M Company Common Stock;1,660,453 > > ================================================ > ! sed '1d;/;/!d' stock # delete headings and everything but data lines BAC;Bank of America Corporation Com;238,059,612 CSCO;Cisco Systems, Inc.;28,159,455 INTC;Intel Corporation;22,501,784 MSFT;Microsoft Corporation;23,363,118 VZ;Verizon Communications Inc. Com;5,744,385 KO;Coca-Cola Company (The) Common;3,752,569 MMM;3M Company Common Stock;1,660,453 sed '1d;/;/{s/;.*//p};d' stock # delete all non essential data BAC CSCO INTC MSFT VZ KO MMM sed '1d;/;/{s/;.*//;H};${g;l};d' stock # use the l command to see what's really there! \nBAC\nCSCO\nINTC\nMSFT\nVZ\nKO\nMMM$ sed '1d;/;/{s/;.*//;H};${g;s/.//;s/\n/, /g;l};d' stock # refine refine BAC, CSCO, INTC, MSFT, VZ, KO, MMM$ sed '1d;/;/{s/;.*//;H};${g;s/.//;s/\n/, /g;q};d' stock # all done! BAC, CSCO, INTC, MSFT, VZ, KO, MMM