Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
unix:sed_et_awk [2009/03/06 11:54]
panda more stuffs
unix:sed_et_awk [2010/01/12 13:29] (current)
Line 1: Line 1:
 +Voici en quelques exemples, quelques indices de l'​incroyable efficacité de la lessive Sed couplée au détergent Awk.
 +
 +====== Sed ======
 +
 +Remplacer toutes les occurences du mot "​tache"​ par le mot "​blancheur"​ dans le fichier mon_linge, on redirige le tout vers le fichier mon_linge_propre :
 +<​code>​
 +$ sed s/​tache/​blancheur/​g mon_linge > mon_linge_propre
 +</​code>​
 +Remplacer tous les debuts de ligne par un "​."​ dans le fichier mon_linge, on redirige le tout vers mon_linge_bien_range :
 +<​code>​
 +$ sed s/^/./ mon_linge > mon_linge_bien_range
 +</​code>​
 +Remplacer tous les fins de ligne par un "​."​ dans le fichier mon_linge, on redirige le tout vers mon_linge_bien_range :
 +<​code>​
 +$ sed s/$/./ mon_linge > mon_linge_bien_range
 +</​code>​
 +Effacer toutes les lignes contenant le mot "​tache"​ dans le fichier mon_linge, on redirige le tout vers le fichier mon_linge_propre :
 +<​code>​
 +$ sed /tache/d mon_linge > mon_linge_propre
 +</​code>​
 +Effacer toutes les lignes contenant le mot "​tache"​ et remplacer tous les fins de ligne par un "​.",​ on redirige vers mon_linge_qui_sent_bon :
 +<​code>​
 +$ sed -e '​s/​$/​./'​ -e  '​s/​.*tache.*/​\\0/'​ > mon_linge_qui_sent_bon
 +</​code>​
 +
 +
 +
 +
 +====== Awk ======
 +
 +
 +Afficher la 2eme colonne ( PID ) du resultat d'un ps aux :
 +<​code>​
 +$ ps aux|awk '​{print $2}'
 +</​code>​
 +Afficher la 2eme colonne ( PID ) du resultat d'un ps aux en le faisant précéder d'un label :
 +<​code>​
 +$ ps aux|awk '​{printf("​PID:​ %s\n"​),​ $2}'
 +</​code>​
 +Afficher la 2eme colonne ( PID ) du resultat d'un ps aux en le faisant précéderd'​un label et en affichant l'​utilisateur :
 +<​code>​
 +$ ps aux|awk '​{printf("​PID:​ %s utilise par %s\n"​),​ $2, $1}'
 +</​code>​
 +Afficher l'/​etc/​passwd bien rangé :
 +<​code>​
 +$ awk -F: '​{printf("​Utilisateur:​ %s\nUID: %s\nGID: %s\nNom: %s\nHome: %s\nShell: %s\n", $1, $3, $4, $5, $6, $7)}' /etc/passwd
 +</​code>​
 +Afficher les users dont le shell est /bin/bash
 +<​code>​
 +awk -F: '​$7=="/​bin/​bash"​ {print $1}' /etc/passwd
 +</​code>​
 +Utiliser les fonctions mathématiques :
 +<​code>​
 +$ echo "3 4" | awk '​{print int($1+$2)}'​
 +</​code>​
 +(affiche normalement 7, si tout se passe bien)
 +
 +Utiliser les fonctions mathématiques (2):
 +<​code>​
 +ls -1sk /usr/bin | sort -n | awk '$1 > 500'
 +</​code>​
 +(affiche le nom des executables de /usr/bin dont la taille est supérieure a 500 k)
 +
 +
 +
 +
 +
 +
 +
 +====== Sed + Awk ======
 +
 +Le but de la manip était de passer de proftpd "​classic"​ à proftpd-mysql+proftpd administrator (http://​proftpd-adm.sourceforge.net/​)
 +
 +En entrée, un fichier de type passwd contenant username, passwd, uid, gid, etc..
 +<​code>​
 +$ cat /​etc/​proftpd.passwd ​
 +64telecom:​$1$YVOCtxyK$jQEyhesyMwECPgHP0Yh1O0:​111:​65534::/​home/​commun/​ftp-externe/​64telecom:/​bin/​false
 +bgsa:​$1$Dzy3LXzx$5z4OrKHQjxEINcg5XIrBl.:​111:​65534::/​home/​commun/​ftp-externe/​bgsa:/​bin/​false
 +mpsftp:​$1$dNm0LqxW$E7t4TuNkv/​srqp4HRL3Xz1:​111:​65534::/​home/​commun/​ftp-externe/​mpsftp:/​bin/​false
 +mpsftp1:​$1$YTfhVzwS$iBUOELFxp.fT3tH7GjPd5.:​111:​65534::/​home/​commun/​ftp-externe/​mpsftp/​mpsftp1:/​bin/​false
 +..
 +(150 lignes)
 +</​code>​
 +
 +En sortie, des INSERT INTO en veux-tu, en voilà, afin d'​insérer tout ça dans une base de données MySQL. Un exemple ce que je voulais:
 +<​code>​
 +INSERT INTO usertable (userid, passwd, homedir, shell, uid, gid, count, lastlogin, lastlogout, expiration, disabled, det_name, det_mail, det_adress, det_notes) VALUES ('​mobisfraf83',​ '​$1$WVPoRVPU$gWEuzxgS7ZZ2mN/​BYVedd0',​ '/​home/​commun/​ftp-externe/​mobisfraf83',​ '/​bin/​false',​ '​2154',​ '​10001',​ '​0',​ '​0000-00-00 00:​00:​00',​ '​0000-00-00 00:​00:​00',​ '​0000-00-00 00:​00:​00',​ '​0',​ '​mobisfraf83',​ '​mobisfraf83',​ '​mobisfraf83',​ '​mobisfraf83'​);​
 +</​code>​
 +
 +Sed et Awk, c'est un peu la fusion de 2 super Sayen dans Dragon Ball Z. J'en veux pour exemple mon code:
 +<​code>​
 +#!/bin/sh
 +a="​2000"​
 +for i in `cat /​etc/​proftpd.passwd`
 +do      ​
 +        echo $i \ | 
 +        cut -d":"​ -f 1,2,6 | \
 +        sed 's/\:/ /g' | \
 +        awk -v sq="'"​ '​{print "​INSERT INTO usertable (userid, passwd, homedir, shell, uid, gid, count, lastlogin, lastlogout, expiration, disabled, det_name, det_mail, det_adress, det_notes) VALUES ('"'"'"​ $1 "'"'"',​ " "'"'"'"​ $2 "'"'"',​ " "'"'"'"​ $3 "'"'",'​ " sq "/​bin/​false"​ sq ", " sq "​111"​ sq ", " sq "​10001"​ sq ", " sq "​0"​ sq ", " sq "​0000-00-00 00:​00:​00"​ sq ", " sq "​0000-00-00 00:​00:​00"​ sq ", " sq "​0000-00-00 00:​00:​00"​ sq ", " sq "​0"​ sq ", '"'"'"​ $1 "'"'"',​ " "'"'"'"​ $1 "'"'"',​ " "'"'"'"​ $1 "'"'"',​ " "'"'"'"​ $1 "'"'"'"​ "​);"​}'​ | \
 +        sed s/111/$a/g
 +        a=$(expr $a + 1)
 +done
 +</​code>​
 +Explications:​
 +echo affiche sur la sortie les lignes du fichier 1 à 1. cut découpe et prend les colonnes 1, 2, 6 avec comme séparateur ":"​. sed remplace les 2 points par une espace. awk fait son boulôt en affichant ce qui reste là où je lui demande de les afficher ($1, $2, $3). À noter: le garçon est TRES CHIANT en ce qui concerne le traitement des singles quotes (vraiment!). J'ai bidouillé un peu, mais ça fonctionne (il existe plusieurs manières de traiter les singles quotes, Google is your friend). sed termine la marche en remplaçant la chaine 111 par une variable que j'​incrémente de 1 à chaque fois et qui commence à 2000 (l'UID des utilisateurs).
 +
 +On sauvegarde et on execute. 150 requêtes en un claquement de doigt. ​
 +Moi je dis, MESSIEURS..
 +
 +Mais subtil rebondissement,​ l'​admin etant une grosse moule il ne supporte pas la taille gigantesque de ce script et decide de l'​ecrire un un seul statement de awk, evitant un nombre incalculable (enfin si, tres calculable) de generations de processus pour le reduire a un seul
 +<​code>​
 +awk -F: -v s="'"​ -v c=", " -v "​a=2000"​ '​{print "​INSERT INTO usertable (userid, passwd, homedir, shell, uid, gid, count, lastlogin, lastlogout, expiration, disabled, det_name, det_mail, det_adress, det_notes) VAL
 +UES (" s $1 s c s $2 s c s $6 s c s "/​bin/​false"​ s c s a++ s c s "​10001"​ s c s "​0"​ s c s "​0000-00-00 00:​00:​00"​ s c s "​0000-00-00 00:​00:​00"​ s c s "​0000-00-00 00:​00:​00"​ s c s "​0"​ s c s $1 s c s $1 s c s $1 s c s $
 +1 s "​);"​ }' /​etc/​proftpd.passwd
 +</​code>​
 +
 +Des lors l'​admin contemple son oeuvre et derriere son apparence de goret immonde se trouve une ame de poete, il lui faut utiliser les qualites intrinseques de awk et ne pas souiller son appel de vilains flags inutiles et reserves aux tacherons:
 +<​code>​
 +awk 'BEGIN { sep="​\047,​ \047"; a=2000; FS=":"​ } {print "​INSERT INTO usertable (userid, passwd, homedir, shell, uid, gid, count, lastlogin, lastlogout, expiration, disabled, det_name, det_mail, det_adress, det_notes) VALUES (\047" $1 sep $2 sep $6 sep "/​bin/​false"​ sep a++ sep "​10001"​ sep "​0"​ sep "​0000-00-00 00:​00:​00"​ sep "​0000-00-00 00:​00:​00"​ sep "​0000-00-00 00:​00:​00"​ sep "​0"​ sep $1 sep $1 sep $1 sep $1 "​\047);"​ }' /​etc/​proftpd.passwd
 +</​code>​
 +
 +Ici on utilise BEGIN qui est un pattern particulier utilise pour matcher avant la premiere ligne.
 +
 +Notre admin, fort de sa maitrise nouvelle du puissant awk, decide qu'il a envie d'​afficher les lignes de son fichier proftpd.passwd,​ mais a l'​envers. Il se lance dans la reecriture du celebre tac:
 +
 +<​code>​
 +awk     '​END ​   { for (i = NR - 1; i >= 0; i--) { print lines[i]; }}
 +                { lines[i++] = $0 }'
 +</​code>​
 +
 +Ici c'est le pattern particulier END qui est utilise.
 +
 +Note: Sed et Awk peuvent également etre utilisés en cascade ( pipe: | ) pour encore plus de fraicheur.
  
unix/sed_et_awk.txt · Last modified: 2010/01/12 13:29 (external edit)