Quelques scripts Unix

Recherche de processus

Ce script simple adapte la commande ps à des systèmes d'exploitation, car les paramètres de cette commande changent suivant les systèmes. Toute personne travaillant sur plusieurs systèmes est rapidement agacée par des comportements de commandes qui diffèrent suivant la machine à qui il s'adresse.

Ce script permet de connaître les informations sur les processus associés à des commandes lancées par l'utilisateur. Ces informations sont extraites de la commande ps, en ne gardant que la partie concernant la commande passée en paramètre.
Par exemple  'exec_rproc ksh '  fournit l'affichage:

       F S UID   PID  PPID   C P TTY  TIME CMD
   40001 A 212 34636 34898   0      -  0:00 ksh
  240001 A 212 34898 33896   0      -  0:00 ksh
  240001 A 212 35608 35358   0  pts/3  0:00 ksh

Le script commence par vérifier la présence d'un paramètre ou de l'option -h en première position.

#! /bin/sh # exec_rproc : recherche processus sex=`uname` # le système d'exploitation id=`logname` # le nom de l'utilisateur # 1. Au moins un paramètre; option -h: demande d'aide if [ $# = 0 ] || [ "$1" = '-h' ] ; then echo \* \* echo \* \* Recherche de processus : rp nom_executable echo \* \* ' rp "mat*" #' processus commençant par mat echo \* \* exit 1 fi

Ensuite on adapte le script aux paramètres de la commande "ps" qui ne sont pas les mêmes suivant la version d'unix utilisée ("SunOS", "Linux" ou "AIX").

# 2. Adaptation au système d'exploitation # sur SunOS ps | grep "mat*" # sur Linux ps -xu | grep "mat*" # sur AIX ps -xu astier| grep "mat*" if [ $sex = Linux ]; then # echo 'USER PID %CPU %MEM SIZE RSS TTY STAT START TIME COMMAND' cmd_ps='ps -xu '; coupe="-c1-20,30-"; fil=. elif [ $sex = SunOS ]; then # echo ' UID PID PPID C STIME TTY TIME CMD' cmd_ps='ps -ef '; coupe=-c1-22,39-; fil=`logname` elif [ $sex = AIX ] then # echo 'F S UID PID PPID C PRI NI ADDR ... TTY TIME CMD' cmd_ps="ps -lu $id "; coupe="-c1-32,61-"; fil='.' fi

Enfin la commande "ps" et l'extraction des résultats sont effectués. Il faut remarquer l'utilisation de "egrep" pour garder à la fois la première ligne de l'affichage fourni par "ps" et les lignes concernant la commande.

# 3. Commande effective $cmd_ps | cut $coupe | egrep "PID|$fil" | egrep "PID|$1" | grep -v egrep

Peut-on créer ou écraser un fichier ?

Dans certaines situations de création de fichier, on veut éviter d'écraser un fichier de même nom, qui existe déjà, et dont on avait oublié l'existence.
Le script ci-après teste l'existence et la possibilité de créer un fichier, dont le nom est passé en paramètre. Il renvoie, suivant le cas:
  1 :  si le fichier existe et l'utilisateur répond non à la demande d'écrasement
  2 :  si le fichier existe et n'est pas modifiable
  3 :  si le fichier n'existe pas, mais le répertoire n'est pas modifiable
  4 :  si le script est utilisé avec 0 ou plus d'un paramètre
  0 :   dans les autres cas

# autoriseCreation.sh (31 mars 2004) # autoriseCreation nomFichier fic= # fichier étudié (premier paramètre) # 1. Quelques constantes NSCRIPT=`basename $0` # nom du script _echo() { # adapté aux séquences d'échappement if [ `uname` = Linux ]; then echo -e $* else echo $* fi } GRAS="\\033[1;31;47m" # 31:rouge 34: bleu FIN="\\033[0m" # 2. Vérifier l'existence d'un paramètre if [ $# -ne 1 ]; then _echo $GRAS _echo "+" _echo " + ! ! ! Il faut un paramètre" _echo " + `basename $0` fichier" _echo " + exemple `basename $0` resultat" _echo "+"$FIN exit 4 fi fic=$1 # 3. Traitement effectif if [ -s $fic ] && [ -f $fic ]; then # fichier ordinaire, non vide if [ -w $fic ]; then _echo "Voulez-vous écraser $fic (oui/non) ? \c" read rep if [ "$rep" != oui ]; then exit 1; fi # utilisateur ne veut pas else exit 2 # fichier protégé en écriture fi elif [ ! -w `dirname $fic` ]; then exit 3; # répertoire non modifiable fi

Les gros fichiers

Ce script donne les fichiers d'une arborescence dont la taille dépasse une valeur donnée, exprimée en bloc (512 octets) ou en kilo.octets. Il est utilisé avec deux paramètres: le nom d'un répertoire et une indication de taille (qui est: un entier positif éventuellement suivi de k, pour indiquer une taille en octets).
Voici un exemple d'affichage souhaité:
 + Répertoire divers
TAILLE    NOM                (taille en k octets)
1584         divers/cpp/coursCpp.pdf
3672         divers/gvim61.exe
3736         divers/julie/atelier.zip
 +  3 fichier(s) d'au moins 1000k

Exemples de commandes:
grosFic   courrier   1000k
grosFic   ~/exec   300
Le premier appel demande les fichiers de plus d'un méga.octets; le second demande les fichiers de plus de 300 blocs.

L'introduction du script indique les paramètres, et définit quelques constantes; puis les vérifications sur les paramètres sont effectuées, avec la prise en compte des deux possibilités d'indiquer la taille, soit en bloc (elle est alors convertie en kilo) soit en kilo actets.

# grosFic.sh (19 mars 2004) # Fichiers de grande taille # grosFic.sh ~ 1000 # fichiers de plus de 1000 blocs # grosFic.sh ~ 1000k # fichiers de plus de 1000k octets rep=$1 # nom du répertoire de départ tk=$2 # taille en k octets (100t) # # # # # # # # # # # # # Quelques constantes # # # # # # # # # # # # # NSCRIPT=`basename $0` # nom du script # Affichage, avec interprétation des "séquences escape" A_=echo; if [ `uname` = Linux ]; then A_='echo -e'; fi # Attributs d'affichage; marque de séquence <ESC>[, soit "\\033[" GRAS="\\033[1;31;47m" # rouge sur fond blanc FIN="\\033[0m" # fin # # # # # # # # # # # # # Vérifications # # # # # # # # # # # # # # Vérifier 2 paramètres if [ $# -ne 2 ]; then $A_ $GRAS echo "+" echo " + ! ! ! Il faut deux paramètres" echo " + `basename $0` repertoire taille_k_octets" echo " + exemple ie03.sh divers 100k" $A_ "+$FIN" exit 1 # Vérifier premier paramètre est un répertoire elif ! [ -d $1 -a -r $1 -a -x $1 ]; then $A_ $GRAS echo "+" echo " + ! ! ! $1 doit être un répertoire accessible" $A_ "+$FIN" exit 2 fi # Deuxième paramètre: il commence par un chiffre, puis 88 ou 88k # et convertir un nombre de blos en k.octets if (echo $2 | grep "^[1-9][0-9]*$" > /dev/null ) || (echo $2 | grep "^[1-9][0-9]*k$" > /dev/null ) then case "$2" in [0-9]*k) tk=$2 ;; [0-9]*) let tk=$2/2; tk=${tk}k;; esac else $A_ $GRAS echo "+" echo " + ! ! ! $2 est une valeur numérique incorrecte"; $A_ "+$FIN" exit 3; fi Le traitement proprement dit demande à la commande find de trouver les fichiers dont la taille dépasse la valeur fournie; puis le nombre de fichiers est évaluée et l'affichage des fichiers, avec leur taille, est effectué par la commande ls. # # # # # # # # # # # # # Traitement # # # # # # # # # # # # # # fics = les noms de fichiers dont la taille dépasse $tk fics=`find $rep -type f -size +$tk`; # nbf = nombre de fichiers nbf=`echo $fics | wc -w | tr -s ' ' `; # Pas de fichier, ou afficher par ls, les noms et taille if [ $nbf -eq 0 ] then $A_ "+ + ${GRAS}Aucun fichier$FIN n'a une taille supérieure à $tk" else echo "+" echo " + Répertoire $rep (taille en k octets):" $A_ "${GRAS}TAILLE$FIN ${GRAS}NOM$FIN" ls -s1 $fics $A_ " + $GRAS$nbf fichier(s)$FIN d'au moins $tk" echo "+" fi

Mot dans quel fichier source ?

Ce script permet la recherche de mots dans des fichiers sources en C++, c'est-à-dire dont l'extension est .h, .cpp, .cc ou .C. Voici un d'appel, et les résultats fournis:
            dansSourceC ../cpp rat.h
        ./rat/rat.C:3:#include "rat.h"
        ./rat/testop.C:3:#include "rat.h"
        + + A partir de /dptinfo/users/astier/app/cpp, 'rat.h' trouvé dans 2 fichiers
        + + ./rat/rat.C ./rat/testop.C
Les paramètres du script sont un nom de répertoire et un mot.

Les premières lignes du script introduisent le sens des paramètres et quelques constantes utilisées.

# dansSourceC (19 mars 2004) Recherche de fichiers C contenant un mot # dansSourceC . INT_MAX # dansSourceC ../C++ INT_MAX rep=$1 # répertoire à explorer mot=$2 # mot à chercher EXTENSIONS="h cpp C cc" # extensions des fichiers parcourus # # # # # # # # # # # # # Quelques constantes # # # # # # # # # # # # # NSCRIPT=`basename $0` # nom du script # Affichage, avec interprétation des "séquences escape" A_=echo; if [ `uname` = Linux ]; then A_='echo -e'; fi # Attributs d'affichage; marque de séquence &lt;ESC>[, soit "\\033[" GRAS="\\033[1;31;47m" # rouge sur fond blanc FIN="\\033[0m" # fin

Puis on effectue des vérifications sur le nombre de paramètres et la validité du premier paramètre, qui doit être un répertoire qui puisse être parcouru (droits "rx").

# # # # # # # # # # # # # Vérifications # # # # # # # # # # # # # # Vérifier 2 paramètres if [ $# -ne 2 ]; then $A_ "$GRAS" echo "+" echo " + ! ! ! Il faut deux paramètres" echo " + $NSCRIPT répertoire mot" echo " + Exemple $NSCRIPT divers TabDisp" $A_ "+ $FIN" exit 1 # Vérifier paramètre est un répertoire elif ! [ -d $1 ]; then $A_ "$GRAS" echo "+" echo " + ! ! ! $1 doit être un répertoire" $A_ "+$FIN" exit 2 # Vérifier droits rx sur $1 elif [ ! -r $1 ] || [ ! -x $1 ]; then $A_ "$GRAS" echo "+" echo " + ! ! ! $1 doit être un répertoire accessible" $A_ "+$FIN" exit 3 fi

Enfin le traitement, qui commence par établir la liste de tous les fichiers (variable fics ) qui contiennent le mot cherché, en examinant successivement chaque extension étudiée.
Si le nombre de fichiers trouvés est non nul, on affiche chaque ligne contenant le mot recherché.

# # # # # # # # # # # # # Traitement # # # # # # # # # # # # # cd $rep # Liste des noms de fichiers, pour chaque extension, contenant $mot fics=""; # cumul des noms de fichiers for e in $EXTENSIONS do nf=`find . -type f -name "*.$e" -exec grep -wl "$mot" {} \;` fics=$fics" "$nf done # Nombre de fichiers trouvés nfic=`echo $fics | wc -w | tr -s ' '` # Afficher nom de fichier et lignes contenant $mot if [ $nfic -eq 0 ] ; then $A_ "+ + '$mot' ${GRAS}non trouvé${FIN} à partir de $PWD" else # Afficher les lignes contenant $mot grep -wn "$mot" $fics # Remplacer séparateur \n par espace fics=`echo $fics | tr '\n' ' '` echo + $A_ "+ + A partir de $PWD, '$mot' ${GRAS}trouvé dans $nfic fichiers${FIN}" echo "+ + $fics" echo + fi # </pre>

Envoi de fichiers par courriers

Ce script permet d'envoyer plusieurs fichiers par courrier électronique; le destinataire reçoit un fichier au format "tar.gz". Exemple d'utilisation:
    envoi_fichiers   toto@machine.fr   *.h *.C
S'il n'y a pas de paramètres le script affiche un bref mode d'emploi.

!/bin/sh # exec_ef envoi de fichier(s) groupés et compressés # exemples MAP=OUI exec_ef $ADR4 tmp exec* # exec_ef $ADR4 tmp exec* # 1. Principales variables adr= # adresse du destinataire fics= # fichiers à regrouper et compresser nomfic=lesfics.gz # nom de la pièce attachée TMP=/tmp/tmp.$LOGNAME # un fichier temporaire

Ensuite on définit quelques informations qui facilitent la programmation du script et l'affichage. En particulier on définit la date et l'heure courante, et $a_ comme étant la commande echo, avec interprétation des suites d'échappement (les options sont différentes sur "Linux" ou "AIX").

# 2. Quelques informations: NSCRIPT, DATE, HMS, GRAS, FIN function ladate { # calcule DATE et HMS local jour quant qmois annee date +"%w %d %m %Y %T" | read jour quant qmois annee HMS qmois=12 # Quel jour $1 ? case $jour in 0) jour=dimanche;; 1) jour=lundi;; 2) jour=mardi;; 3) jour=mercredi;; 4) jour=jeudi;; 5) jour=vendredi;; 6) jour=samedi;; esac # # variable de type tableau pour le mois set -A mois janvier février mars avril mai juin juillet aout \ septembre octobre novembre décembre DATE="$jour, $quant ${mois[$qmois-1]} $annee" } # ladate # calcule DATE et HMS (hh:mm:ss) NSCRIPT=`basename $0` # nom du script # pour la couleur DSQ="\\033["; FIN=$DSQ"0m"; GRAS=$DSQ"1;31;47m" # 31:rouge 34: bleu a_=echo # commande d'affichage if [ `uname` = LINUX ]; then a_='echo -e'; fi # mode mise au point (variable MAP définie et non vide)? if [ ${#MAP} -gt 0 ]; then MAP=":" ; else MAP="! :"; fi # les constantes typeset -r MAP NSCRIPT FIN GRAS DATE HMS Puis on vérifie qu'il y a au moins deux paramètres. # 3. Erreur ou aide if [ $# -lt 2 ]; then $a_ $GRAS+ $a_ " + Envoi d'un ou plusieurs fichiers compressés" $a_ " + $NSCRIPT adresse_électronique fichier_1 ..." $a_ ' +' $a_ " + Exemple: $NSCRIPT astérix@uderzo.com fic1.html fic2* " $a_ +$FIN exit 1 fi On vérifie également que le premier paramètre est une adresse personnelle, c'est à dire contient un '@' et un nom de machine terminée par '.xx' ou '.xxx'. # 4. Récupérer l'adresse, l'enlever de la liste et la vérifier adr=$1 shift # commence par une lettre, contient @: "^[A-Za-z].*@" # termine par x.yy ou x.yyy: "[.][a-z]\{2,3\}$" if ! echo $adr|grep "^[A-Za-z].*@"|grep "[^.][.][a-z]\{2,3\}$">/dev/null then # adresse incorrecte $a_ $GRAS $a_ " ! ! ! Adresse incorrecte: $adr" $a_ $FIN exit 2; fi On vérifie que tous les noms de fichiers, qui figurent après l'adresse, existent. # 5. Vérifier que tous les fichiers existent fics=$* if ! ls $fics > /dev/null 2>&1; then $a_ $GRAS # un message par fichier for i in $fics; do if ls $i > /dev/null 2>&1 ; then : else $a_ "+ + fichier $i introuvable" fi done $a_ " ! ! ! PAS de courrier envoyé" $a_ $FIN exit 3; fi Si la variable MAP est une chaîne non vide, on arrête le script; cela permet de faire des essais sans envoyer effectivement du courrier. # 6. Arrêt si on est en phase de mise au point if $MAP ; then $a_ "+ + Pas d'envoi des fichier(s) $GRAS $fics$FIN" $a_ "+ + à $GRAS $adr$FIN ($DATE, $HMS)" exit 0 fi Enfin le traitement proprement dit est effectué. Tous les fichiers sont regroupés en un seul (par tar), qui est compressé (par gzip), puis recodé (par uuencode), pour n'avoir que des octets où le premier bit est à zéro.
Le courrier est alors écrit avec ce fichier de nom $TMP.gz.asc en attaché. # 7. Création et envoi du courrier tar -cf $TMP $fics # regrouper (crée ttt) gzip -f $TMP # compresser (crée ttt.gz uuencode $TMP.gz $nomfic > $TMP.gz.asc # convertir pour code 7 bits cat << FIN. | mail -s"le $DATE, $HMS" $adr Ce jour: $DATE ($HMS), envoi de $fics mail -s"le $DATE" $adr ~r $TMP.gz.asc FIN. # $a_ "+ + Envoi des fichier(s) $GRAS $fics$FIN" $a_ "+ + $GRAS $fics$FIN" $a_ "+ + à $GRAS $adr$FIN ($DATE)$FIN"

Quelques liens