Archives de catégorie : AWK

AWK et sa fonction system tellement pratique

Hello les ami(e)s !!! J’espère que vous allez bien dans cette période difficile à l’approche d’un durcissement de confinement. Difficile de pouvoir reprendre une vie normale alors que nos hôpitaux se remplissent.

Cependant il faut continuer à garder le moral et alles de l’avant. Certes le soleil nous donne un peu plus envie d’aller dehors mais il redonne tout de même une belle dose d’espérance.

Bref aujourd’hui parlons ou reparlons de awk. C’est souvent un outil méconnu ou tout du moins que l’on connaît pour faire des choses très simples et on se limite dans son utilisation grâce aux facilités apportées par la ligne de commandes (pipe etc).

AWK la simplicité à l’état pur

Je vous rappelle que j’avais fait il y a pas loin de 2 ans quelques tutos en guise de formation à awk. Ce petit cours de awk se limite à du petit oneline mais il permet déjà de faire des choses supers sympas je trouve :

  • élimination des doublons
  • compteurs
  • analyse de logs
  • conditions
  • génération de sql

Vous pouvez retrouver tout cela dans la playlist dédiée au scripting saison 1.

Mais parfois avec un petit rien en plus et on peut faire vraiment beaucoup plus. Je ne vous parle pas là de créer un vrai script AWK, multiligne. Non on reste dans le oneline avec encore un gros degré de simplicité.

Alors pour la démo prenons la CLI kubectl pour manipuler les pods. Je pars de cette commande mais vous pouvez partir de tout ce que vous souhaitez, l’idée est de manipuler la CLI.

Donc prenons la liste des pods avec un petit filtre pour afficher qu’une colonne.

kubectl get pods -o wide | awk '{print $6}'

Collectons la colonne des ip des pods (d’où le $6). Et maintenant pour manipuler un peu plus nous pouvons par exemple filtrer sur le statut des pods et leurs ips.

kubectl get pods -o wide | awk '($3 ~ "Running") && ($6 ~ "10.233.64.1.*") { print $6}'

Et notre commande system ?

On combine donc deux conditions. avec && et on applique un ~ pour la recherche sur base de regex.

C’est déjà pas mal mais là on se dit ça serait kool de lister tous les pods et de leur appliquer une commande system.

Concentrons nous juste sur un ping par exemple :

kubectl get pods -o wide | awk '($3 ~ "Running") && ($6 ~ "10.233.64.1.*") {print $1;system("ping -c 1 "$7)}'

Et on oubliera pas l’option -c1 pour ne pas boucler sur ping et ne réaliser qu’un seul ping (on pourrait définir un timeout plus approprié).

Nous avons simplement utilisé la fonction system de awk pour passer une commande… système. Simple est kool. On retrouve finalement ce que sait très bien faire xargs.

Alors avec notre kubectl on peut faire finalement quelque chose d’utile comme par exemple supprimé tous les pods en état evicted :

kubectl get pods -o wide | awk '($3 ~ "Evicted") {print "\n Drop >> "$1;system("kubectl delete pods "$1)}'

Et oui on retrouve là toute la facilité de awk car en plus vous le remarquez, on se permet même d’écrire une ligne avant. On pourrait en écrire une après ou encore faire un compteur pour dire le nombre de pods traités. Simple non ?

Bref AWK dans ce cas de figure permet de faire du personnalisable avec très peu de chose et sa fameuse commande system.

Alors si vous aimez ce genre de choses ou ces thématiques, venez vous joindre à la communauté Xavki. Vous pouvez aussi vous abonner pour ne pas manquer les prochaines vidéos.

L’objectif de la chaine est simple : se former et progresser ensemble

Enfin si vous voulez vous faire la main avec bash et si vous disposez de légères notions avec docker, vous pouvez vous rendre sur cette série de vidéos. Une formation qui vous conduira à réaliser un script bash permettant d’instancier des conteneurs docker avec systemd et ssh.

Un bon moyen de joindre l’utile à l’agréable avec un poil de docker et à la sortie la possiblité d’utiliser des conteneurs comme des machines virtuelles avec un gros gain de temps au provisionning.

Se prendre au jeu de AWK

Enfin si vous avez du temps et que vous êtes du genre curieux. Vous pouvez poursuivre sur le chemin de awk. En scriptant bien sûr et en utilisant des évolutions de ce langage comme le gawk ou encore le mawk. Ce dernier m’a été évoqué en parlant de performance. Il semblerait le plus rapide pour processer de la données réparties sur différents fichiers. Un article fait un petit focus sur les performances du mawk ici.

Cependant après avoir fait quelques tests maisons je ne parviens pas à des resultats explicites pour pouvoir en faire une réelle démonstration.

Toujours sur la performance en matière de processer du fichier text, vous pouvez aussi vous reporter à cet article. Celui-ci fait une analyse comparative entre le nawk, gawk et mawk assez intéressante. Il s’agit de faire un comparatif sur l’utilisation de la mémoire par ses derniers.

[Awk] : comment lister les ports des vhosts d’un apache ? (gsub, match, substr et regex)

Awk c’est un peu mon petit préféré pour faire du oneline en manipulant des lignes. Et une fois de plus, il est encore bien sympa pour nous lister les ports utilisés pour chaque vhost d’un apache. Bon on se fait un peu plaisir vous allez voir… et c’est pas pour frimer.

En gros, on veut un truc qui nous dise :

nom_du_vhost  =>> numéro_port

y compris si nous avons plusieurs ports (80 et 443).

Et en une ligne, voici le code que j’ai pu écrire :

awk '/.*:[0-9]{1,3}>/ && /[^#]/
{match($0,/:[0-9]{1,3}>/);
gsub("/.*/"," ",FILENAME);
print FILENAME"=>>", 
substr($0, RSTART+1, RLENGTH-2)}'
/etc/apache2/*.*

Explications de cette commande d’une ligne un peu chargée :

  • 1ère ligne : restriction des lignes traitées en limitant aux lignes contenant « : » puis 1 à 3 chiffres allant de 0 à 9 et qui ne contient pas de « # » (pour éviter les lignes de commentaires)
  • 2ème ligne : capture du pattern du port encadre de « : » et « > »
  • 3ème ligne : nettoyage du filename en retournant uniquement le nom de fichier
  • 5ème ligne : récupération du pattern de la regex

C’est un peu compliqué mais cela permet surtout de faire un peu de la manipulation pour s’entretenir en awk.

Et vous vous feriez comment pour réaliser ce genre d’opération ?

[Linux] : lister les ports en écoute sur une machine

La base pour les sysadmin, on a souvent besoin pour diagnostiquer des problèmes de lister les ports en écoute sur un serveur. Deux binaires peuvent réaliser ceci sans problème : netstat ou lsof.

Avec lsof :

sudo lsof -i -P | egrep LISTEN | awk -F ":" '{print $2}' |sort -u


Avec netsat :

netstat -ntaup | awk '/LISTEN/ && match($0,/:[0-9]+/) {print substr( $0, RSTART+1, RLENGTH )}' | sort -u


De la même manière on peut lister les connexions établies pour connaître les machines connectées :

netstat -ntaup | awk '/ESTABLISHED/ {print $5}'


[Awk][Linux] : Lister les processus non killable et le stopper avec ps aux + awk

La commande PS possède une multitude d’options et un affiche un grand nombre d’éléments. On ne va pas tous les passés en revue rassurez vous. Aujourd’hui, je vous propose un moyen simple de lister les process non killable. C’est ultra simple car il suffit de lire la colonne status de PS.

Cette colonne contient généralement une ou deux lettres :

  • R : en cours
  • S : interrompable
  • s : c’est une session maitre
  • l : multi-threadé
  • < : priorité haute
  • + : processus d’arrière plan
  • D : non killable

C’est se dernier cas qui peut être plus gênant car ce process ne peut être arrêté. Et pour lister les processus en fonction d’un statut c’est awk :

ps aux | awk '{if ($8 ~ "D") print $0}'

Pour le stopper ce n’est pas simple car un kill -9 du pid ne marchera pas. On peut éventuellement tenter un reboot forcé :

reboot -n -f

C’est un peu moche c’est clair. J’imagine qu’avec un lsof on peut aussi identifié le filesystem utilisé et le démonté. C’est pas beaucoup plus jolie.

Plus d’infos sur le site noah.org et bien sûr la man page de PS

[Awk] : convertir un csv en sql

Encore une petite commande pour débuter et bien pratique. Nhésitez pas en commentaire à partager votre expérience sur ce genre de conversion.

Awk va nous permettre de facilement convertir un csv en sql. D’ailleurs je suis en train de me dire qu’il faudrait que je passe un peu de temps dessus pour faire en sorte qu’il s’adapte automatiquement à toutes les longueurs de csv voir à récupérer l’entête pour les noms de champs ça serait plus malin.

En tout cas pour l’instant voici comment j’utilise régulièrement awk pour convertir mes fichiers csv (ou autre parfois) en sql.

# contenu du csv
cat attention.csv 
1;xav;dd;25d;28
2;paul;aa;25f;100

# ligne de commande
cat attention.csv | awk -F ";" '{print "INSERT INTO matable (champs1, champs2, champs3, champs4, champs5) values ('\''"$1"'\'', '\''"$2"'\'', '\''"$3"'\'', '\''"$4"'\'', '\''"$5"'\'');"}'

# le résultat
INSERT INTO matable (champs1, champs2, champs3, champs4, champs5) values ('1', 'xav', 'dd', '25d', '28');
INSERT INTO matable (champs1, champs2, champs3, champs4, champs5) values ('2', 'paul', 'aa', '25f', '100');
INSERT INTO matable (champs1, champs2, champs3, champs4, champs5) values ('3', 'thierry', 'bb', '14g', '75');

Donc :

  • tout simplement on défini le séparateur avec -F
  • on print en insérant les variable des champs
  • la seule suptilité c’est d’échapper les quotes.

Interagir avec l’utilisateur via un prompt – Awk

Awk  c’est bien et je l’ai déjà dit on le sous exploite souvent. Il permet souvent de manipuler des fichier notamment des tableaux. Mais bon Awk c’est aussi un language assez complet qui permet de faire des programmes plus étendus et pas que des one-liners.

Le truc bête est méchant c’est de commencer par interagir avec l’utilisateur. Par exemple on va lui poser une question et afficher la réponse. En gros c’est du awk pour les nuls.

Voici comment faire :

#!/usr/bin/awk

BEGIN{
        printf("Entrez votre prénom: ");
        getline nom < "-"
        print "Bonjour "nom" !"
}


Donc tout se devine:

  • on oublie pas de préciser la localisation du programme
  • on utilise le BEGIN (début de fichier ou en-tête)
  • on affiche une invite
  • on récupère le contenu rentré par le user et on le sotck dans la variable nom
  • et on affiche le résultat

Et on exécute façon awk :

└─ $ ▶ awk -f prompt.awk 
Entrez votre prénom: xavki
Bonjour xavki !


photo of person holding h cutout decor

Photo by rawpixel.com on Pexels.com

[AWK] : comment utiliser une variable shell dans awk ?

Awk est  un language bien sympa mais parfois on hésite à l’utiliser car il faut se prendre la tête à lui faire asser des variables. Du coup on tort le truc dans tous les sens alors qu’il suffit parfois de récupérer les variables shell pour les réutiliser dans awk.

Je vous propose deux options mais j’ai une grosse préférence pour la première.

La première c’est d’uliser l’option -v :

└─ $ ▶ variable="toto";awk -v var="$variable" 'BEGIN {print var}'
toto


La seconde en lui passant une variable d’environnement avec ENVIRON :

└─ $ ▶ variable=toto awk 'BEGIN {print ENVIRON["variable"]}'
toto


[AWK] : créer un serveur web minimaliste

Dans un post précédent, nous avions vu comment lancer un serveur web en python. Cela ne prenait qu’une seule ligne par les miracles de python.

Mais saviez vous qu’avec AWK vous pouviez faire pareil ? c’est fou non ? ben oui c’est possible mais attention cela ne se fait pas en une seule ligne (ou sinon elle sera bien loin du one-liner).

#!/usr/bin/gawk -f
BEGIN {
if (ARGC < 2) { print "Usage: wwwawk  file.html"; exit 0 }
	Concnt = 1;
        while (1) {
        RS = ORS = "\r\n";
        HttpService = "/inet/tcp/8080/0/0";
        getline Dat < ARGV[1];
        Datlen = length(Dat) + length(ORS);
        while (HttpService |& getline ){
		if (ERRNO) { print "Connection error: " ERRNO; exit 1}
                print "client: " $0;
                if ( length($0) < 1 ) break;
        }
        print "HTTP/1.1 200 OK"             |& HttpService;
        print "Content-Type: text/html"     |& HttpService;
        print "Server: wwwawk/1.0"          |& HttpService;
        print "Connection: close"           |& HttpService;
        print "Content-Length: " Datlen ORS |& HttpService;
        print Dat                           |& HttpService;
        close(HttpService);
        print "OK: served file " ARGV[1] ", count " Concnt;
        Concnt++;
      }
} 

 

Après avoir créé votre fichier donnez lui les droits qui vont bien (755) par exemple et créez une fichier file.html. Lancez le script et rendez vous sur votre localhost:8080 et le fichier sera servi.

Je trouve ça trop fort quand même. Pas vous ?

Source : bon article de tuxgraphics

[Bash][AWK] : Lister les commandes le top de vos commandes

L’historique de Linux est utilisable via le binaire « history » ou avec un simple vi de « .bash_history ». Mais on l’utilise plus régulièrement à l’aide de la commande ctrl+r en tapant les mots à rechercher dans votre historique. Un bon moyen pour relancer une commande déjà utilisée.

Mais on peut faire d’autres choses avec notamment avoir un vrai système de log de l’historique avec la mise en place d’un archivage de vos commandes. On reverra cela plus tard.

person writing on notebook

Photo by Lukas on Pexels.com

Utiliser les statistiques de votre historique c’est aussi un bon moyen de voir ce que vous faites le plus souvent. Et du coup vous pouvez y trouver de bonnes idées pour créer les alias les plus adéquates pour gagner en performance devant votre clavier.

Un bon moyen pour faire ces statistiques :

history | awk '{a[$2]++}END{for(i in a){print a[i] " " i}}' | sort -rn | head

Donc :

  • on lance history pour travailler dessus
  • on utilise awk pour dresser la liste des top commandes
  • on ordonne le tout avec un sort

 

[AWK][Linux] : Supprimer les doublons de votre PATH… RS FS et ORS OFS

Un truc typique sur linux c’est d’ajouter des chemins à votre PATH pour accéder à des binaires mais sans vérifier que ce chemin existe déjà. Du coup on perd un peu en perf et c’est très moche.

Je ne vous propose pas de commande pour vérifier si un chemin existe déjà mais plutôt une commande qui vous permettra de recréer votre variable $PATH sans les doublons. Ainsi vous pouvez ajouter cela au moment du chargement de vos variables d’environnement.

export PATH=`echo -n $PATH | awk -v RS=":" '{ if (!x[$0]++){printf s $0 ; s=":"}}'`

L’option RS de awk s’appelle record separator. Il permet de définir les séparateur de ligne.

L’autre option souvent utilisée avec awk c’est FS pour fiels separator. On défini alors les séparateur de champs comme par exemple le « ; » pour les fichiers de type csv.

gaming cards on hands

Photo by Midhun Joy on Pexels.com

Ensuite pour aller un petit peu plus loin on peut aussi utiliser les output de ces options à savoir OFS ou ORS. Ainsi c’est l’inverse on définit comment on souhaite afficher les spérateur de champs ou de ligne.

Par exemple :

awk -F':' 'BEGIN{OFS=">";} {print $3,$4;}' /etc/passwd
1001>1001
1002>1002
1003>1003

En gros on parcours le passwd en définissant les champs par un FS valant « : ». Puis pour la sortie du résultat on redéfinie un séparateur de champ avec un OFS valant « > ».

Il y a aussi dans les options courantes pour les oneliner :

  • NR (number rows) : affiche le nombre de ligne
  • NF (number fields) : nombre de champs

Ainsi on pourrait afficher le nombre de ligne dont le nombre de champs vaut une certaine valeur.

AWK est un vrai couteau suisse pour qui sait l’utiliser.

[AWK][Tips] : supprimer les lignes en doublon

Celle-là elle est facile me diront certains mais bon c’est parfois utile de le rappeler. Awk est un outil bien pratique pas toujours plus court que les autres mais tellement facile à pipper.

Comment supprimer les lignes en doublons d’un fichier ? qu’elles soient à la suite ou non d’ailleurs.

Autant qu’en bash si on utilise le binaire sort cela va vite avec cat monfichier | sort -u … mais avec awk on peut se creuser la tête.

Voici donc la solution :

awk '! a[$0]++' fichier.txt 

Donc on créé un tableau (array) avec pour clé $0 soit le contenu de la ligne. Et on affiche le contenu dès lors que la ligne suivante est différente (on incrémente de 1 avec le ++.

En un peu plus long il y avait :

awk '!($0 in a) {a[$0];print}' fichier.txt 

Que dire de plus plus ? pas grand chose car le but est de faire court.

[AWK][Tips] : calculer le cumul d’une colonne

Awk est un très bon outil. On peut l’utiliser soit de manière peu développée (oneliner) ou plus élaborée comme un vrai language de programmation. Généralement on l’utilise pour son côté conci sur une ligne.

Aujourd’hui je vous propose un classique de AWK à savoir calculer le cumul d’une colonne. Rien de bien sorcier et en plus ça permet de bien entrer dans le sujet. Je reviendrai plus tard sur les séparateurs mais on va se limiter à FS pour commencer. FS pour Fields Separator. Par exemple pour un fichier de type csv -FS= »; ». Ensuite on peut appeler les colonnes en fonction de leur ordre $1 = première colonne. Et $0 représente toute la ligne.

Ainsi avec un fichier contenant :

└─ $ ▶ cat fichier.txt 
toto;1;2;url
xxx;2;5;url2
yyy;2;6;url3

On a donc 3 lignes de 4 colonnes. On cherche à calculer la somme de la troisème colonne. Rien de plus simple :

# afficher le contenu du fichier
awk '{print $0} fichier.txt'

# pour afficher la troisième colonne uniquement
awk -FS ";" '{print $3}' fichier.txt

# pour calculer le cumul de la colonne 3
awk -FS ";" '{CUMUL += $3} END {print CUMUL}' fichier.txt

Donc là on y est :

  • on défini le séparateur de champs
  • on créé une variable CUMUL dans laquel on ajoute la valeur de la colonne 3 à chaque ligne
  • et en dernière ligne on affiche le contenu de la variable CUMUL

C’est simple non ?

Le gros intérêt c’est de pouvoir « piper » tout cela en appliquant avant des commandes bash, sed….

Promis dans pas longtemps on va revenir sur les FS, OFS, NR, ONR…