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.
d
, ce qui supprime l’espace du motif et passe immédiatement à la ligne suivante. ;
) par une virgule et un espace (“,”) à l’aide de la commande s
(substitut). H
). 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
1d
;
alors concentrons-nous sur ces lignes. /;/
;
à la fin de la ligne et ensuite le ranger dans l’espace d’attente (HS) {s/;.*//;H}
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}
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