Comment utiliser le langage AWK pour manipuler du texte sous Linux
Introduction
Les utilitaires Linux suivent souvent la philosophie de design d'Unix. Les outils sont encouragés à être petits, à utiliser des fichiers texte simples pour l'entrée et la sortie, et à fonctionner de manière modulaire. En raison de cet héritage, nous disposons d'une excellente fonctionnalité de traitement de texte avec des outils comme sed et awk.
awk est à la fois un langage de programmation et un processeur de texte que vous pouvez utiliser pour manipuler les données textuelles de manière très utile. Dans ce guide, vous explorerez comment utiliser l'outil en ligne de commande awk et comment l'utiliser pour traiter du texte.
Syntaxe de base
La commande awk est incluse par défaut dans tous les systèmes Linux modernes, donc vous n'avez pas besoin de l'installer pour commencer à l'utiliser.
awk est particulièrement utile pour traiter des fichiers texte formatés de manière prévisible. Par exemple, il est excellent pour analyser et manipuler des données tabulaires. Il fonctionne ligne par ligne et itère à travers tout le fichier.
Par défaut, il utilise des espaces (espaces, tabulations, etc.) pour séparer les champs. Heureusement, de nombreux fichiers de configuration sur votre système Linux utilisent ce format.
Le format de base d'une commande awk est :
- awk '/search_pattern/ { action_to_take_on_matches; another_action; }' file_to_parse
Vous pouvez omettre soit la partie de recherche, soit la partie d'action de toute commande awk. Par défaut, l'action effectuée si la partie « action » n'est pas fournie est « print ». Cela imprime simplement toutes les lignes qui correspondent.
Si la partie de recherche n'est pas donnée, awk effectue l'action répertoriée sur chaque ligne.
Si les deux sont donnés, awk utilise la partie de recherche pour déterminer si la ligne actuelle reflète le motif, puis effectue les actions sur les correspondances.
Dans sa forme la plus simple, vous pouvez utiliser awk comme cat pour afficher toutes les lignes d'un fichier texte à l'écran.
Créez un fichier favorite_food.txt qui liste les plats préférés d'un groupe d'amis :
- echo "carrot sandy
- wasabi luke
- sandwich brian
- salad ryan
- spaghetti jessica" > favorite_food.txt
Maintenant, utilisez la commande awk pour afficher le fichier à l'écran :
- awk '{print}' favorite_food.txt
Vous verrez le fichier imprimé à l'écran :
carrot sandy
wasabi luke
sandwich brian
salad ryan
spaghetti jessica
Cela n'est pas très utile. Essayons les capacités de filtrage de recherche d'awk en cherchant dans le fichier le texte “sable” :
- awk '/sand/' favorite_food.txt
carrot sandy
sandwich brian
Comme vous pouvez le voir, awk n'imprime maintenant que les lignes qui contiennent les caractères « sable ».
En utilisant des expressions régulières, vous pouvez cibler des parties spécifiques du texte. Pour afficher uniquement la ligne qui commence par les lettres "sand", utilisez l'expression régulière ^sand :
- awk '/^sand/' favorite_food.txt
Cette fois, une seule ligne est affichée :
sandwich brian
De même, vous pouvez utiliser la section d'action pour spécifier quelles informations vous souhaitez imprimer. Par exemple, pour imprimer uniquement la première colonne, utilisez la commande suivante :
- awk '/^sand/ {print $1;}' favorite_food.txt
sandwich
Vous pouvez référencer chaque colonne (délimitée par des espaces) par des variables associées à leur numéro de colonne. Par exemple, la première colonne est $1, la deuxième est $2, et vous pouvez référencer la ligne entière avec $0.
Variables internes et format élargi
La commande awk utilise certaines variables internes pour attribuer certaines informations pendant qu'elle traite un fichier.
Les variables internes que awk utilise sont :
- NOM DU FICHIER: Fait référence au fichier d'entrée actuel.
- FNR : Fait référence au numéro de l'enregistrement actuel par rapport au fichier d'entrée en cours. Par exemple, si vous avez deux fichiers d'entrée, cela vous indiquerait le numéro d'enregistrement de chaque fichier plutôt que le total.
- FS : Le séparateur de champ actuel utilisé pour indiquer chaque champ dans un enregistrement. Par défaut, cela est défini sur des espaces.
- NF: Le nombre de champs dans l'enregistrement actuel.
- NR : Le numéro de l'enregistrement actuel.
- OFS : Le séparateur de champ pour les données de sortie. Par défaut, cela est défini sur un espace.
- ORS : Le séparateur d'enregistrement pour les données de sortie. Par défaut, il s'agit d'un caractère de nouvelle ligne.
- RS : Le séparateur d'enregistrements utilisé pour distinguer les enregistrements séparés dans le fichier d'entrée. Par défaut, il s'agit d'un caractère de nouvelle ligne.
Vous pouvez changer les valeurs de ces variables à volonté pour correspondre aux besoins de vos fichiers. En général, vous le faites pendant la phase d'initialisation de votre traitement.
Cela nous amène à un autre concept important. La syntaxe awk est légèrement plus complexe que ce que vous avez utilisé jusqu'à présent. Il y a aussi des blocs BEGIN et END optionnels qui peuvent contenir des commandes à exécuter avant et après le traitement du fichier, respectivement.
Cela rend notre syntaxe étendue ressemblant à ceci :
- awk 'BEGIN { action; }
- /search/ { action; }
- END { action; }' input_file
Les mots-clés BEGIN et END sont des ensembles spécifiques de conditions, tout comme les paramètres de recherche. Ils correspondent avant et après que le document ait été traité.
Cela signifie que vous pouvez modifier certaines des variables internes dans la section BEGIN. Par exemple, le fichier /etc/passwd est délimité par des deux-points (:) au lieu d'espaces.
Pour imprimer la première colonne de ce fichier, exécutez la commande suivante :
- awk 'BEGIN { FS=":"; }
- { print $1; }' /etc/passwd
root
daemon
bin
sys
sync
games
man
. . .
Vous pouvez utiliser les blocs BEGIN et END pour imprimer des informations sur les champs que vous imprimez. Utilisez la commande suivante pour transformer les données du fichier en un tableau, bien espacé avec des tabulations en utilisant \t :
- awk 'BEGIN { FS=":"; print "User\t\tUID\t\tGID\t\tHome\t\tShell\n--------------"; }
- {print $1,"\t\t",$3,"\t\t",$4,"\t\t",$6,"\t\t",$7;}
- END { print "---------\nFile Complete" }' /etc/passwd
Vous verrez cette sortie :
User UID GID Home Shell
--------------
root 0 0 /root /bin/bash
daemon 1 1 /usr/sbin /bin/sh
bin 2 2 /bin /bin/sh
sys 3 3 /dev /bin/sh
sync 4 65534 /bin /bin/sync
. . .
---------
File Complete
Comme vous pouvez le voir, vous pouvez formater les choses assez joliment en profitant de certaines fonctionnalités de awk.
Chacune des sections élargies est optionnelle. En fait, la section d'action principale elle-même est optionnelle si une autre section est définie. Par exemple, vous pouvez faire des choses comme ceci :
- awk 'BEGIN { print "We can use awk like the echo command"; }'
Et vous verrez ce résultat :
We can use awk like the echo command
Maintenant, voyons comment chercher du texte dans les champs de la sortie.
Recherche de terrain et expressions composées
Dans l'un des exemples précédents, vous avez imprimé la ligne dans le fichier favorite_food.txt qui commençait par « sand ». C'était facile car vous cherchiez le début de la ligne entière.
Que se passerait-il si vous vouliez découvrir si un modèle de recherche correspondait au début d'un champ à la place?
Créez une nouvelle version du fichier favorite_food.txt qui ajoute un numéro d'article devant la nourriture de chaque personne :
- echo "1 carrot sandy
- 2 wasabi luke
- 3 sandwich brian
- 4 salad ryan
- 5 spaghetti jessica" > favorite_food.txt
Si vous voulez trouver tous les aliments de ce fichier qui commencent par "sa", vous pourriez commencer par essayer quelque chose comme ceci :
- awk '/sa/' favorite_food.txt
Cela montre toutes les lignes qui contiennent « sa » :
1 carrot sandy
2 wasabi luke
3 sandwich brian
4 salad ryan
Ici, vous correspondez à toute instance de « sa » dans le mot. Cela inclut des choses comme « wasabi » qui a le motif au milieu, ou « sandy » qui n'est pas dans la colonne que vous souhaitez. Dans ce cas, vous êtes uniquement intéressé par les mots commençant par « sa » dans la deuxième colonne.
Vous pouvez dire à awk de ne faire correspondre qu'au début de la deuxième colonne en utilisant cette commande :
- awk '$2 ~ /^sa/' favorite_food.txt
Comme vous pouvez le voir, cela nous permet de ne rechercher qu'au début de la deuxième colonne pour une correspondance.
La partie field_num ~ spécifie que awk ne doit prêter attention qu'à la deuxième colonne.
3 sandwich brian
4 salad ryan
Vous pouvez tout aussi facilement rechercher des choses qui ne correspondent pas en incluant le caractère “!” avant le tilde (~). Cette commande renverra toutes les lignes qui n'ont pas un aliment qui commence par “sa” :
- awk '$2 !~ /^sa/' favorite_food.txt
1 carrot sandy
2 wasabi luke
5 spaghetti jessica
Si vous décidez plus tard que vous êtes uniquement intéressé par les lignes qui ne commencent pas par « sa » et que le numéro d'article est inférieur à 5, vous pourriez utiliser une expression composée comme celle-ci :
- awk '$2 !~ /^sa/ && $1 < 5' favorite_food.txt
Cela introduit quelques nouveaux concepts. Le premier est la capacité d'ajouter des exigences supplémentaires pour que la ligne corresponde en utilisant l'opérateur &&. En l'utilisant, vous pouvez combiner un nombre arbitraire de conditions pour que la ligne corresponde. Dans ce cas, vous utilisez cet opérateur pour ajouter une vérification que la valeur de la première colonne est inférieure à 5.
Vous verrez cette sortie :
1 carrot sandy
2 wasabi luke
Vous pouvez utiliser awk pour traiter des fichiers, mais vous pouvez également travailler avec la sortie d'autres programmes.
Traitement des sorties d'autres programmes
Vous pouvez utiliser la commande awk pour analyser la sortie d'autres programmes plutôt que de spécifier un nom de fichier. Par exemple, vous pouvez utiliser awk pour extraire l'adresse IPv4 de la commande ip.
La commande ip a affiche l'adresse IP, l'adresse de diffusion et d'autres informations sur toutes les interfaces réseau de votre machine. Pour afficher les informations de l'interface appelée eth0, utilisez cette commande :
- ip a s eth0
Vous verrez les résultats suivants :
2571: eth0@if2572: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:0b brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.11/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
Vous pouvez utiliser awk pour cibler la ligne inet et ensuite imprimer simplement l'adresse IP :
- ip a s eth0 | awk -F '[\/ ]+' '/inet / {print $3}'
Le drapeau -F indique à awk de délimiter par des barres obliques ou des espaces en utilisant l'expression régulière [\/ ]+. Cela divise la ligne inet 172.17.0.11/16 en champs séparés. L'adresse IP se trouve dans le troisième champ car les espaces au début de la ligne comptent également comme un champ, puisque vous avez utilisé des espaces ainsi que des barres obliques comme délimiteurs. Notez que awk a traité les espaces consécutifs comme un seul espace dans ce cas.
La sortie affiche l'adresse IP :
172.17.0.11
Vous trouverez de nombreux endroits où vous pouvez utiliser awk pour rechercher ou analyser la sortie d'autres commandes.
Conclusion
À ce stade, vous devriez avoir une compréhension de base de la façon dont vous pouvez utiliser la commande awk pour manipuler, formater et imprimer sélectivement des fichiers texte et des flux de texte. Cependant, Awk est un sujet beaucoup plus vaste et constitue en fait un langage de programmation complet avec une assignation de variables, des structures de contrôle, des fonctions intégrées, et plus encore. Vous pouvez l'utiliser dans vos propres scripts pour formater le texte de manière fiable.
Pour en savoir plus sur awk, vous pouvez lire le livre de domaine public gratuit de ses créateurs qui entre beaucoup plus dans les détails.
