Apprendre les commandes Linux : awk
Dans le cas de cet article, le titre Learning Linux Commands : awk peut être un peu trompeur. Et c’est parce que awk est plus qu’une commande, c’est un langage de programmation à part entière. Vous pouvez écrire des scripts awk pour des opérations complexes ou vous pouvez utiliser awk à partir de la ligne de commande. Le nom signifie Aho, Weinberger et Kernighan (oui, Brian Kernighan), les auteurs du langage, qui a été lancé en 1977, donc il partage le même esprit Unix que les autres utilitaires classiques *nix.
Si vous vous habituez à la programmation C ou si vous la connaissez déjà, vous verrez quelques concepts familiers dans awk, d’autant plus que le 'k' dans awk représente la même personne que le 'k' dans K&R, la bible de la programmation C. Vous aurez besoin de quelques connaissances en ligne de commande sous Linux et éventuellement de quelques bases de script, mais la dernière partie est facultative, car nous essaierons d’offrir quelque chose pour tout le monde. Un grand merci à Arnold Robbins pour tout son travail impliqué dans awk.
Dans ce tutoriel, vous allez apprendre :
- Que fait
awk? Comment cela fonctionne-t-il ? - Concepts de base
d’awk - Apprenez à utiliser
awkà travers des exemples de ligne de commande
Apprentissage de la commande awk à travers divers exemples de ligne de commande sur Linux
Que fait awk ?
awk est un utilitaire/langage conçu pour l’extraction de données. Si le mot « extraction » vous dit quelque chose, c’est parce que awk était autrefois l’inspiration de Larry Wall lorsqu’il a créé Perl. awk est souvent utilisé avec sed pour effectuer des tâches de manipulation de texte utiles et pratiques, et cela dépend de la tâche si vous devez utiliser awk ou Perl, mais aussi de vos préférences personnelles. Tout comme sed, awk lit une ligne à la fois, effectue une action en fonction de la condition que vous lui donnez et affiche le résultat.
L’une des utilisations les plus simples et les plus populaires d’awk consiste à sélectionner une colonne à partir d’un fichier texte ou de la sortie d’une autre commande. Une chose que je faisais avec awk était, si j’installais Debian sur mon deuxième poste de travail, d’obtenir une liste des logiciels installés à partir de ma boîte principale, puis de la transmettre à aptitude. Pour cela, j’ai fait quelque chose comme ça :
dpkg -l | awk ' {print $2} ' > installed
La plupart des gestionnaires de paquets offrent aujourd’hui cette fonctionnalité, par exemple les options -qa de rpm, mais le résultat est supérieur à ce que je veux. Je vois que la deuxième colonne de la sortie de dpkg -l contient le nom des paquets installés, c’est pourquoi j’ai utilisé $2 avec awk : pour ne me donner que la 2ème colonne.
Concepts de base
Comme vous l’avez remarqué, l’action à effectuer par awk est entourée d’accolades, et toute la commande est citée. Mais la syntaxe est awk ' condition { action }'. Dans notre exemple, nous n’avions aucune condition, mais si nous voulions, par exemple, vérifier uniquement les paquets liés à vim installés (oui, il y a grep, mais c’est un exemple, et pourquoi utiliser deux utilitaires alors que vous ne pouvez en utiliser qu’un seul ?), nous aurions fait ceci :
dpkg -l | awk ' /'vim'/ {print $2} '
Cette commande afficherait tous les paquets installés dont le nom contient « vim ». Une chose à propos d’awk, c’est qu’il est rapide. Si vous remplacez « vim » par « lib », sur mon système, cela donne 1300 paquets. Il y aura des situations où les données avec lesquelles vous devrez travailler seront beaucoup plus volumineuses, et c’est l’une des parties où awk brille.
Quoi qu’il en soit, commençons par les exemples, et nous expliquerons quelques concepts au fur et à mesure. Mais avant cela, il serait bon de savoir qu’il existe plusieurs dialectes et implémentations d’awk, et les exemples présentés ici traitent de GNU awk, en tant qu’implémentation et dialecte. Et en raison de divers problèmes de guillemets, nous supposons que vous utilisez bash, ksh ou sh, nous ne supportons pas (t)csh.
Exemples de commandes awk
Consultez certains des exemples ci-dessous pour comprendre awk et comment vous pouvez l’appliquer dans des situations sur votre propre système. N’hésitez pas à suivre et à utiliser certaines de ces commandes dans votre terminal pour voir la sortie que vous obtenez.
Imprimez uniquement les colonnes un et trois à l’aide de stdin.
awk ' {print $1,$3} 'Imprimez toutes les colonnes à l’aide de stdin.
awk ' {print \$0} 'Imprimez uniquement les éléments de la colonne 2 qui correspondent au motif à l’aide de stdin.
awk ' /'pattern'/ {print $2} 'Tout comme
makeoused,awkutilise-fpour obtenir ses instructions à partir d’un fichier, ce qui est utile lorsqu’il y a beaucoup à faire et que l’utilisation du terminal serait peu pratique.awk -f script.awk inputfileExécuter le programme à l’aide des données du fichier d’entrée.
awk ' program ' inputfileClassique « Hello, world » en
awk.awk "BEGIN { print \"Hello, world!!\" }"Affiche ce qui est entré sur la ligne de commande jusqu’à EOF (^D).
awk '{ print }'awkpour le classique « Hello, world ! » (rendez-le exécutable avecchmodet exécutez-le tel quel).#! /bin/awk -f BEGIN { print "Hello, world!" }Commentaires dans les scripts
awk.This is a program that prints \ "Hello, world!" and exitsDéfinissez le FS (séparateur de champs) comme null, par opposition aux espaces, par défaut.
awk -F "" 'program' filesFS peut également être une expression régulière.
awk -F "regex" 'program' filesImprimera <'>. Voici pourquoi nous préférons les coquilles Bourne. 🙂
awk 'BEGIN { print "Here is a single \ quote <'\''>" }'Imprimez la longueur de la ligne la plus longue.
awk '{ if (length(\$0) > max) max = \ length(\$0) } END { print max }' inputfileImprimez toutes les lignes de plus de 80 caractères.
awk 'length(\$0) > 80' inputfileImprime chaque ligne comportant au moins un champ (NF signifie Number of Fields).
awk 'NF > 0' dataImprimez sept nombres aléatoires de 0 à 100.
awk 'BEGIN { for (i = 1; i <= 7; i++) print int(101 * rand()) }'Affiche le nombre total d’octets utilisés par les fichiers du répertoire courant.
ls -l . | awk '{ x += $5 } ; END \ { print "total bytes: " x }' total bytes: 7449362Affiche le nombre total de kilo-octets utilisés par les fichiers du répertoire courant.
ls -l . | awk '{ x += $5 } ; END \ { print "total kilobytes: " (x + \ 1023)/1024 }' total kilobytes: 7275.85Imprime la liste triée des noms de connexion.
awk -F: '{ print $1 }' /etc/passwd | sortImprime le nombre de lignes d’un fichier, car NR signifie Nombre de lignes.
awk 'END { print NR }' inputfileImprimez les lignes paires dans un fichier. Comment imprimeriez-vous les lignes impaires ?
awk 'NR % 2 == 0' dataImprime le nombre total d’octets des fichiers qui ont été modifiés pour la dernière fois en novembre.
ls -l | awk '$6 == "Nov" { sum += $5 } END { print sum }'Expression régulière correspondant à toutes les entrées du premier champ qui commencent par un j majuscule.
awk '$1 /J/' inputfileExpression régulière correspondant à toutes les entrées du premier champ qui ne commencent pas par un j majuscule.
awk '$1 !/J/' inputfileÉchapper aux guillemets doubles dans
awk.awk 'BEGIN { print "He said \"hi!\" \ to her." }'Estampes « <A>bcd »
echo aaaabcd | awk '{ sub(/a+/, \ "<A>"); print }'Exemple d’attribution ; Essaie 🙂
ls -lh | awk '{ owner = $3 ; $3 = $3 \ " 0wnz"; print $3 }' | uniqModifiez l’inventaire et imprimez-le, à la différence que la valeur du deuxième champ sera diminuée de 10.
awk '{ $2 = $2 - 10; print \$0 }' inventoryMême si la zone six n’existe pas dans l’inventaire, vous pouvez la créer et lui attribuer des valeurs, puis l’afficher.
awk '{ $6 = ($5 + $4 + $3 + $2); print \ $6' inventoryOFS est le séparateur de champ de sortie et la commande affichera « a ::c :d » et « 4 » car bien que le champ deux soit annulé, il existe toujours donc il est compté.
echo a b c d | awk '{ OFS = ":"; $2 = "" > print \$0; print NF }'Un autre exemple de création de champs ; Comme vous pouvez le voir, le champ entre $4 (existant) et $6 (à créer) est également créé (comme $5 avec une valeur vide), donc le résultat sera « a ::c :d ::new » « 6 ».
echo a b c d | awk ’{ OFS = ":"; \ $2 = ""; $6 = "new" > print \$0; print NF }’Jeter trois champs (les derniers) en modifiant le nombre de champs.
echo a b c d e f | awk ’\ { print "NF =", NF; > NF = 3; print \$0 }’Il s’agit d’une expression régulière qui définit le séparateur de champ sur l’espace et rien d’autre (correspondance de motifs non gourmande).
FS=[ ]Cela n’affichera que « a ».
echo ' a b c d ' | awk 'BEGIN { FS = \ "[ \t\n]+" } > { print $2 }'Affiche uniquement la première correspondance de RE (expression régulière).
awk -n '/RE/{p;q;}' file.txtDéfinit FS à \\
awk -F\\ '...' inputfiles ...Si nous avons un enregistrement comme :
John Doe
1234 Unknown Ave.
Doeville, MA
Ce script définit le séparateur de champs sur saut de ligne afin qu’il puisse facilement fonctionner sur les lignes.BEGIN { RS = "" ; FS = "\n" } { print "Name is:", $1 print "Address is:", $2 print "City and State are:", $3 print "" }Avec un fichier à deux champs, les enregistrements seront imprimés comme suit :
"field1 :field2champ3 ; champ4
…; ..."
Parce que ORS, le séparateur d’enregistrement de sortie, est défini sur deux sauts de ligne et OFS est « ; ”awk 'BEGIN { OFS = ";"; ORS = "\n\n" } > { print $1, $2 }' inputfileCela affichera 17 et 18, car la sortie ForMaT est définie pour arrondir les valeurs à virgule flottante à la valeur entière la plus proche.
awk 'BEGIN { > OFMT = "%.0f" # print numbers as \ integers (rounds) > print 17.23, 17.54 }'Vous pouvez utiliser printf principalement de la manière dont vous l’utilisez en C.
awk 'BEGIN { > msg = "Dont Panic!" > printf "%s\n", msg >} 'Imprime le premier champ sous la forme d’une chaîne de 10 caractères, justifiée à gauche, et de $2 normalement, à côté.
awk '{ printf "%-10s %s\n", $1, \ $2 }' inputfileRendre les choses plus jolies.
awk 'BEGIN { print "Name Number" print "---- ------" } { printf "%-10s %s\n", $1, \ $2 }' inputfileExemple simple d’extraction de données, où le deuxième champ est écrit dans un fichier nommé « phone-list ».
awk '{ print $2 > "phone-list" }' \ inputfileÉcrivez les noms contenus dans $1 dans un fichier, puis triez et affichez le résultat dans un autre fichier (vous pouvez également ajouter avec >>, comme vous le feriez dans un shell).
awk '{ print $1 > "names.unsorted" command = "sort -r > names.sorted" print $1 | command }’ inputfileImprimera 9, 11, 17.
awk 'BEGIN { printf "%d, %d, %d\n", 011, 11, \ 0x11 }'Recherche simple pour foo ou bar.
if (/foo/ || /bar/) print "Found!"Opérations arithmétiques simples (la plupart des opérateurs ressemblent beaucoup à C).
awk '{ sum = $2 + $3 + $4 ; avg = sum / 3 > print $1, avg }' gradesCalculatrice simple et extensible.
awk '{ print "The square root of", \ $1, "is", sqrt($1) }' 2 The square root of 2 is 1.41421 7 The square root of 7 is 2.64575Imprime tous les enregistrements entre le début et la fin.
awk '$1 == "start", $1 == "stop"' inputfileLes règles BEGIN et END sont exécutées exactement une fois, avant et après tout traitement d’enregistrement.
awk ' > BEGIN { print "Analysis of \"foo\"" } > /foo/ { ++n } > END { print "\"foo\" appears", n,\ "times." }’ inputfileRecherche à l’aide du shell.
echo -n "Enter search pattern: " read pattern awk "/$pattern/ "'{ nmatches++ } END { print nmatches, "found" }' inputfileConditionnel simple.
awk, comme C, prend également en charge les opérateurs ?:.if (x % 2 == 0) print "x is even" else print "x is odd"Imprime les trois premières trames de chaque enregistrement, une par ligne.
awk '{ i = 1 while (i <= 3) { print $i i++ } }’ inputfileImprime les trois premières trames de chaque enregistrement, une par ligne.
awk '{ for (i = 1; i <= 3; i++) print \$i }'Quitter avec un code d’erreur différent de 0 signifie que quelque chose ne va pas. Voici un exemple.
BEGIN { if (("date" | getline date_now) <= 0) { print "Can't get system date" > \ "/dev/stderr" exit 1 } print "current date is", date_now close("date") }Imprime awk fichier1 fichier2.
awk 'BEGIN { > for (i = 0; i < ARGC; i++) > print ARGV[i] > }’ file1 file2Supprimer des éléments dans un tableau.
for (i in frequencies) delete frequencies[i]Recherchez les éléments du tableau.
foo[4] = "" if (4 in foo) print "This is printed, even though foo[4] \ is empty"Une variante
awkde ctime() en C. C’est ainsi que vous définissez vos propres fonctions dansawk.function ctime(ts, format) { format = "%a %b %d %H:%M:%S %Z %Y" if (ts == 0) ts = systime() # use current time as default return strftime(format, ts) }Un générateur de nombres aléatoires Cliff.
BEGIN { _cliff_seed = 0.1 } function cliff_rand() { _cliff_seed = (100 * log(_cliff_seed)) % 1 if (_cliff_seed < 0) _cliff_seed = - _cliff_seed return _cliff_seed }Anonymiser un journal Apache (les adresses IP sont aléatoires).
cat apache-anon-noadmin.log | \ awk 'function ri(n) \ { return int(n*rand()); } \ BEGIN { srand(); } { if (! \ ($1 in randip)) { \ randip[$1] = sprintf("%d.%d.%d.%d", \ ri(255), ri(255)\ , ri(255), ri(255)); } \ $1 = randip[$1]; print \$0 }'
Conclusion
Comme vous pouvez le voir, avec awk, vous pouvez faire beaucoup de traitement de texte et d’autres choses astucieuses. Nous n’avons pas abordé de sujets plus avancés, comme les fonctions prédéfinies d’awk, mais nous vous en avons montré suffisamment (nous l’espérons) pour commencer à vous en souvenir comme d’un outil puissant.
