Le répertoire /proc est en fait un pseudo-système de fichiers. Les fichiers dans le répertoire /proc sont un miroir du système en cours d'exécution et des processus du noyau, et contiennent des informations et des statistiques sur elles.
bash$ cat /proc/devices Character devices: 1 mem 2 pty 3 ttyp 4 ttyS 5 cua 7 vcs 10 misc 14 sound 29 fb 36 netlink 128 ptm 136 pts 162 raw 254 pcmcia Block devices: 1 ramdisk 2 fd 3 ide0 9 md bash$ cat /proc/interrupts CPU0 0: 84505 XT-PIC timer 1: 3375 XT-PIC keyboard 2: 0 XT-PIC cascade 5: 1 XT-PIC soundblaster 8: 1 XT-PIC rtc 12: 4231 XT-PIC PS/2 Mouse 14: 109373 XT-PIC ide0 NMI: 0 ERR: 0 bash$ cat /proc/partitions major minor #blocks name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq 3 0 3007872 hda 4472 22260 114520 94240 3551 18703 50384 549710 0 111550 644030 3 1 52416 hda1 27 395 844 960 4 2 14 180 0 800 1140 3 2 1 hda2 0 0 0 0 0 0 0 0 0 0 0 3 4 165280 hda4 10 0 20 210 0 0 0 0 0 210 210 ... bash$ cat /proc/loadavg 0.13 0.42 0.27 2/44 1119 bash$ cat /proc/apm 1.16 1.2 0x03 0x01 0xff 0x80 -1% -1 ? bash$ cat /proc/acpi/battery/BAT0/info present: yes design capacity: 43200 mWh last full capacity: 36640 mWh battery technology: rechargeable design voltage: 10800 mV design capacity warning: 1832 mWh design capacity low: 200 mWh capacity granularity 1: 1 mWh capacity granularity 2: 1 mWh model number: IBM-02K6897 serial number: 1133 battery type: LION OEM info: Panasonic bash$ fgrep Mem /proc/meminfo MemTotal: 515216 kB MemFree: 266248 kB
Des scripts shells peuvent extraire des données à partir de certains des fichiers de /proc. [86]
FS=iso grep $FS /proc/filesystems # iso9660
kernel_version=$( awk '{ print $3 }' /proc/version )
CPU=$( awk '/model name/ {print $5}' < /proc/cpuinfo ) if [ "$CPU" = "Pentium(R)" ] then lance_des_commandes ... else lance_des_commandes_différentes ... fi vitesse_cpu=$( fgrep "cpu MHz" /proc/cpuinfo | awk '{print $4}' ) # La vitesse d'exécution actuelle (en MHz) du CPU de votre machine. # Sur un portable, cela peut varier suivant que vous utilisez la batterie #+ ou le secteur.
#!/bin/bash # get-commandline.sh # Obtient les paramètres en ligne de commande d'un processus. OPTION=cmdline # Identifie le PID. pid=$( echo $(pidof "$1") | awk '{ print $1 }' ) # Récupère seulement le premier # ^^^^^^^^^^^^^^^^^^ de plusieurs instances. echo echo "ID du processus de (la première instance de) "$1" = $pid" echo -n "Arguments en ligne de commande : " cat /proc/"$pid"/"$OPTION" | xargs -0 echo # Formate la sortie : ^^^^^^^^^^^^^^^ # (Merci pour la correction, Han Holl !) echo; echo # Par exemple : # sh get-commandline.sh xterm
fichier_dev="/proc/bus/usb/devices" texte="Spd" USB1="Spd=12" USB2="Spd=480" vitesse_bus=$(fgrep -m 1 "$texte" $fichier_dev | awk '{print $9}') # ^^^^ s'arrête après la première correspondance. if [ "$vitesse_bus" = "$USB1" ] then echo "Port USB 1.1 découvert." # Faire quelque chose d'appropriée avec USB 1.1. fi
Il est même possible de contrôler certains périphériques avec des commandes envoyées au répertoire /proc.
root# echo on > /proc/acpi/ibm/light
Ceci active Thinklight sur certains modèles Thinkpad d'IBM/Lenovo.
Bien sûr, vous devez faire particulièrement attention quand vous écrivez dans /proc.
Le répertoire /proc contient des sous-répertoires avec des noms numériques inhabituels. Chacun de ces noms correspond à un numéro de processus d'un processus en cours d'exécution. À l'intérieur de ces sous-répertoires, il existe un certain nombre de fichiers contenant des informations sur le processus correspondant. Les fichiers stat et status maintiennent des statistiques sur le processus, le fichier cmdline contient les arguments de la ligne de commande avec lesquels le processus a été appelé et le fichier exe est un lien symbolique vers le chemin complet du processus. Il existe encore quelques autres fichiers, mais ceux-ci sont les plus intéressants du point de vue de l'écriture de scripts.
Exemple 27.2. Trouver le processus associé à un PID
#!/bin/bash # pid-identifier.sh # Donne le chemin complet du processus associé avec ce pid. NBARGS=1 # Nombre d'arguments que le script attend. E_MAUVAISARGS=65 E_MAUVAISPID=66 E_PROCESSUS_INEXISTANT=67 E_SANSDROIT=68 PROCFILE=exe if [ $# -ne $NBARGS ] then echo "Usage : `basename $0` PID" >&2 # Message d'erreur >stderr. exit $E_MAUVAISARGS fi nopid=$( ps ax | grep $1 | awk '{ print $1 }' | grep $1 ) # Cherche le pid dans l'affichage de "ps" car il est le champ #1. # S'assure aussi qu'il s'agit du bon processus, et non pas du processus appelé # par ce script. # Le dernier "grep $1" supprime cette possibilité. # # pidno=$( ps ax | awk '{ print $1 }' | grep $1 ) # fonctionne aussi comme l'indique Teemu Huovila. if [ -z "$nopid" ] # Si, après tous ces filtres, le résultat est une chaîne vide, then #+ aucun processus en cours ne correspond au pid donné. echo "Aucun processus en cours." exit $E_PROCESSUS_INEXISTANT fi # Autrement : # if ! ps $1 > /dev/null 2>&1 # then # Aucun processus ne correspond au pid donné. # echo "Ce processus n'existe pas" # exit $E_PROCESSUS_INEXISTANT # fi # Pour simplifier tout cet algorithme, utilisez "pidof". if [ ! -r "/proc/$1/$PROCFILE" ] # Vérifiez les droits en lecture. then echo "Processus $1 en cours, mais..." echo "Ne peut obtenir le droit de lecture sur /proc/$1/$PROCFILE." exit $E_SANSDROIT # Un utilisateur standard ne peut accéder à certains fichiers de /proc. fi # Les deux derniers tests peuvent être remplacés par : # if ! kill -0 $1 > /dev/null 2>&1 # '0' n'est pas un signal mais # ceci testera s'il est possible # d'envoyer un signal au processus. # then echo "PID n'existe pas ou vous n'êtes pas son propriétaire" >&2 # exit $E_MAUVAISPID # fi fichier_exe=$( ls -l /proc/$1 | grep "exe" | awk '{ print $11 }' ) # Ou fichier_exe=$( ls -l /proc/$1/exe | awk '{print $11}' ) # # /proc/pid-number/exe est un lien symbolique #+ vers le chemin complet du processus appelé. if [ -e "$fichier_exe" ] # Si /proc/pid-number/exe existe, then # alors le processus correspondant existe. echo "Processus #$1 appelé par $fichier_exe" else echo "Processus inexistant" fi # Ce script élaboré peut *pratiquement* être remplacé par # ps ax | grep $1 | awk '{ print $5 }' # Néanmoins, cela ne fonctionnera pas... #+ parce que le cinquième champ de 'ps' est le argv[0] du processus, #+ et non pas le chemin vers l'exécutable. # # Néanmoins, une des deux méthodes suivantes devrait fonctionner. # find /proc/$1/exe -printf '%l\n' # lsof -aFn -p $1 -d txt | sed -ne 's/^n//p' # Commentaires supplémentaires par Stéphane Chazelas. exit 0
Exemple 27.3. État de la connexion
#!/bin/bash NOMPROC=pppd # démon ppp. NOMFICHIERPROC=status # Où chercher. NONCONNECTE=65 INTERVALLE=2 # Mise à jour toutes les deux secondes. nopid=$( ps ax | grep -v "ps ax" | grep -v grep | grep $NOMPROC | awk '{ print $1 }' ) # Trouver le numéro de processus de 'pppd', le 'démon ppp'. # Doit filtrer les lignes de processus générées par la recherche elle-même. # # Néanmoins, comme Oleg Philon l'a indiqué, #+ ceci pourrait être considérablement simplifié en utilisant "pidof". # nopid=$( pidof $NOMPROC ) # # Morale de l'histoire : #+ Quand une séquence de commandes devient trop complexe, cherchez un raccourci. if [ -z "$pidno" ] # Si pas de pid, alors le processus ne tourne pas. then echo "Non connecté." exit $NONCONNECTE else echo "Connecté."; echo fi while [ true ] # Boucle sans fin, le script peut être amélioré ici. do if [ ! -e "/proc/$pidno/$NOMFICHIERPROC" ] # Quand le processus est en cours d'exécution, alors le fichier "status" #+ existe. then echo "Déconnecté." exit $NONCONNECTE fi netstat -s | grep "packets received" # Obtenir quelques statistiques de netstat -s | grep "packets delivered" #+ connexion. sleep $INTERVALLE echo; echo done exit 0 # De cette façon, le script ne se termine qu'avec un Control-C. # Exercices : # ---------- # Améliorer le script pour qu'il se termine suite à l'appui sur la touche # "q". # Rendre le script plus facilement utilisable d'autres façons.
En général, il est dangereux d'écrire dans les fichiers de /proc car cela peut corrompre le système de fichiers ou provoquer une erreur fatale.