Notes pour un cours d'introduction à Linux pour le CEPL
François-René Rideau

Ce cours présente les concepts de base du système Linux. Il ne requiert aucune connaissance préalable, mais s'adresse à des personnes ayant l'ambition de devenir réellement maître du sujet.

0 Remarques préliminaires
1 L'architecture des ordinateurs et de Linux
   1.1 Architecture de Von Neuman
   1.2 Mémoire
   1.3 Architecture virtualisée
   1.4 Persistence
   1.5 Multiplexage des ressources
   1.6 Appels systèmes
   1.7 Droits d'accès
   1.8 Niveaux d'abstraction
2 Le petit monde de Linux
   2.1 Le monde vu par un processus
   2.2 Conventions d'usage
      2.2.1 Paramètres de lancement d'une commande
      2.2.2 Options
      2.2.3 Configuration
      2.2.4 Gestion des erreurs
   2.3 L'arborescence des fichiers
      2.3.1 Noms de fichiers
      2.3.2 Liens durs et liens symboliques
      2.3.3 Droits d'accès des fichiers
      2.3.4 Organisation conventionnelle du système de fichiers
      2.3.5 Trouver des fichiers
   2.4 Les services en réseau
   2.5 L'interface graphique X
   2.6 Initialisation du système
3 Réflexes de base pour survivre
   3.1 Survivre avec l'interface graphique
   3.2 Savoir survivre avec la ligne de commande
   3.3 Utiliser l'aide
   3.4 Pour en savoir plus
   3.5 Apprendre à utiliser un éditeur
   3.6 Habitudes élémentaires de précaution
   3.7 Apprendre à programmer
      3.7.1 Programmation shell
      3.7.2 Programmation de scripts
      3.7.3 Langages de programmation sérieux
      3.7.4 Programmation système
      3.7.5 Programmation ennuyeuse
4 Le shell et ses amis
   4.1 Shell 101
      4.1.1 La notion de shell
      4.1.2 L'offre disponible
      4.1.3 Quel shell apprendre?
      4.1.4 Principe de base du shell
      4.1.5 Vos premières commandes
   4.2 Interaction avec le Shell
      4.2.1 Édition de ligne avec le shell
      4.2.2 Le shell en mode EMACS
      4.2.3 La complétion
      4.2.4 Le terminal sans éditeur
   4.3 Commandes simples
      4.3.1 Invocation d'une commande
      4.3.2 Commandes pour s'en sortir avec les fichiers
      4.3.3 Conventions d'appel pour les commandes
   4.4 Expansion des commandes par le shell
      4.4.1 Variables
      4.4.2 Échappements et guillemets
      4.4.3 Chemins d'accès
      4.4.4 Globbing
      4.4.5 Backquote
      4.4.6 Calculs arithmétiques
      4.4.7 Brace expansion
      4.4.8 Alias
   4.5 Commandes élaborées
      4.5.1 Redirection
      4.5.2 Regroupement de commandes
      4.5.3 Structure
      4.5.4 Fonctions et Scripts
      4.5.5 Programmation Shell Avancée
   4.6 Trucs à connaître
      4.6.1 Job control
      4.6.2 Noms de fichiers cachés
      4.6.3 Noms de fichiers ressemblant à des options
      4.6.4 Noms de fichiers difficiles à reproduire
   4.7 Configuration du shell
   4.8 Quelques amis du shell
      4.8.1 Petits utilitaires
      4.8.2 Contrôler la sortie
      4.8.3 Contrôler l'entrée
      4.8.4 Gérer la divergence des fichiers
      4.8.5 Comprimer et Archiver
      4.8.6 Vous connecter au réseau
      4.8.7 Aide à l'écriture
   4.9 Expressions régulières
5 Applications disponibles sous Linux
   5.1 Applicatifs les plus courants
   5.2 Quel type de documents produire?
   5.3 Correspondance rapide Windows vers Linux
   5.4 Correspondance rapide MacOS vers Linux
   5.5 Différences rapides entre BSD vers Linux
   5.6 Différences rapides entre Linux et les UNIX propriétaires
6 Tout se complique
   6.1 Disquettes, CD-ROMs, etc.
   6.2 Les bibliothèques à liaison dynamiques
   6.3 Gestion du temps
   6.4 Les terminaux
      6.4.1 Principe du terminal
      6.4.2 Configuration du terminal
      6.4.3 Multiplexer son terminal
      6.4.4 Programmer son terminal
      6.4.5 Déboguer son terminal
   6.5 Connexion à distance
   6.6 Administration
   6.7 Impression
   6.8 Compiler un programme
   6.9 Le noyau et ses modules
7 Quelques Exercices
   7.1 Exercice permanent
   7.2 Exercice d'administration de base
   7.3 Exercice de configuration graphique
   7.4 Copie d'écran
   7.5 Burn All GIFs!
   7.6 Pour les plus avancés...

0 Remarques préliminaires

Les notes de cours suivantes sont un document de travail en cours d'élaboration, à l'occasion des cours que j'ai commencé à donner pour le CEPL en octobre 2003. Vous pouvez suivre l'évolution de ces notes de cours sur mon serveur CVS. [Mon serveur CVS n'est plus à jour; j'utilise maintenant monotone.]

Les opinions professées sont les miennes et n'engagent que moi. En particulier, elles n'engagent ni le CEPL, ni mon employeur régulier, ni aucune association ni aucun groupe dont je ferais partie, et encore moins dont je ne ferais pas partie.

Ces notes de cours ne remplacent pas le cours et les travaux pratiques; elles ne se substituent pas non plus aux supports de cours de M. Pascal Bauler; elles constituent un complément théorique. Seule la pratique vous apprendra réellement Linux; ces notes n'ont pas d'autre objet que de vous permettre d'orienter votre pratique et d'en cristalliser plus vite les concepts fondamentaux.

Pour maîtriser Linux, vous devrez en connaître les principes fondamentaux, mais aussi savoir vous y retrouver dans la documentation. Ces notes de cours font systématiquement référence au manuel en-ligne de Linux, et contiennent aussi de nombreuses références à des pages web (notamment dans la section 3.4 "Pour en savoir plus"). Il y a aussi des notes de bas de page, qui se veulent des points de départ utiles à ceux d'entre vous qui voudront explorer un sujet particulier, mais dont la connaissance n'est pas indispensable à l'utilisation de Linux. Il est plus important de comprendre l'essentiel, et pour le reste de savoir ce qui existe et où chercher en cas de problème, que de maîtriser tous les détails de choses somme toute rarement utiles.

Pour ce qui est du mouvement des logiciels libres et de sa philosophie, qui soutendent tout le monde de Linux, voir mon article Le Libre Logiciel et surtout les liens sur lesquels il pointe (section "ressources").

1 L'architecture des ordinateurs et de Linux

Voici un court rappel sur l'architecture des ordinateurs en général, avec des notes sur Linux en particulier. Ce rappel permet aussi de mettre au clair certains concepts et le vocabulaire qui va avec.

1.1 Architecture de Von Neuman

Selon le modèle de machines formalisé par Von Neuman dans les années 1940 et toujours suivi (à quelques variantes près) par tous les ordinateurs à usage général (anglais: general-purpose computer) une machine est constituée d'un processeur (anglais: processor) et d'une mémoire (anglais: memory).

La machine effectue des calculs en exécutant séquentiellement instruction après instruction, des milliers de fois par seconde (de nos jours, en l'an 2003, parfois des milliards de fois).

Le processeur possède un nombre limité de registres (anglais: registers), pouvant chacun représenter un sous-ensemble fini des nombres entiers (de nos jours, presque toujours un nombre binaire sur 32 chiffres, pouvant donc représenter tout nombre positif inférieur à 2 puissance 32).

La mémoire possède un grand nombre de cases ayant chacune son adresse (anglais: address), un numéro qui peut être décrit dans un registre, pouvant chacune contenir un mot (anglais: word), qui peut être lu ou écrit depuis un registre.

Chaque instruction (anglais: instruction) pourra lire un petit nombre de registres ou de cases mémoires (typiquement moins de trois), et en modifier un petit nombre (typiquement une au plus). Chaque opération (anglais: operation) effectuée par chacune de ces instructions sur les registres et la mémoire est très simple: un exemple typique est l'addition de deux mots, le résultat étant stoqué dans un registre.

Les instructions sont elles-mêmes lues dans la mémoire, à l'adresse indiquée par un registre spécial appelé compteur du programme (anglais: program counter) ou pointeur d'instruction (anglais: instruction pointer); le pointeur d'instruction est incrémenté (anglais: incremented) (c'est-à-dire qu'on l'avance un peu) avant l'instruction suivante, à moins qu'il ne soit modifié par l'instruction en cours, alors appelée un saut (anglais: jump). Grâce à des tels sauts, le programme peut effectuer des boucles (anglais: loop) répétitives, de façon à effectuer un travail similaire un grand nombre de fois sur une grande quantité d'informations. Pour pouvoir effectuer des variantes à chaque fois, traiter des cas particulier, savoir arrêter le traitement et sortir d'une boucle, le processeur peut typiquement n'exécuter un saut ou une autre instruction qu'après avoir vérifié un test (anglais: test), qui consiste typiquement à déterminer si deux nombres étaient égaux ou différents.

Pour pouvoir communiquer avec le monde extérieur, l'ordinateur exécute des instructions spéciales dites d'entrée-sortie (anglais: input-output). Souvent (mais pas toujours), cette entrée-sortie prend la forme d'une opération de lecture ou d'écriture dans une case mémoire spéciale — on dit que l'entrée-sortie est mappée en mémoire (anglais: memory-mapped).

Pertinence: la façon dont se font les calculs, par un très grand nombre de petites modifications sur un espace mémoire (anglais: memory space), a une incidence sur la façon dont sont organisées les informations sur lesquelles on travaille, les données (anglais: data). Il est parfois utile de comprendre cette organisation pour agir sur le système (le corriger, l'améliorer). [1]

1.2 Mémoire

La mémoire de travail qui peut être lue ou modifiée à volonté est appelée mémoire vive (MEV) (anglais: random-access memory (RAM)); elle s'efface quand l'ordinateur est éteint ou remis à zéro. Un mémoire ne s'effaçant pas et ne pouvant pas (normalement) être modifiée, la mémoire morte (MEM) (anglais: read-only memory (ROM)) contient le programme de démarrage de l'ordinateur. Le reste de l'espace adressable (anglais: addressable space), correspondant aux numéros de cases mémoire qui ne sont pas occupés pas de la mémoire vive ni de la mémoire morte, ni des entrées-sorties mappées en mémoire, est inutilisé.

Dans les ordinateurs modernes, l'unité d'information traitée est le bit (chiffre binaire (anglais: binary digit)) (b), qui peut contenir un 0 ou un 1. les bits sont souvent groupés en mots de n bits, pouvant chacun représenter 2 puissance n combinaisons différentes, typiquement un nombre entier naturel entre 0 et (2 puissance n) - 1 ou un nombre entier relatif entre -(2 puissance (n-1)) et (2 puissance (n-1))-1. La taille d'un mot, quand elle n'est pas spécifiée, est celle d'un registre de la machine, qui est de nos jours en général 32 bits ou 64 bits.

Les mots de 8 bits sont appelés octet (anglais: byte) (1 B = 8 b), et peuvent représenter un nombre entier entre 0 et 255 (ou entre -128 et +127). Les textes sont composés de caractères (anglais: characters) où chaque caractère est en général stoqué sur un octet (parfois 2, parfois 4, parfois une valeur variable entre 1 et 4).

Les ordinateurs travaillent typiquement sur des mots de 32 bits (soit 4 octets, nombres entre 0 et 4.294.967.295, ou entre -2.147.483.648 et +2.147.483.647) ou pour les plus puissants 64 bits (soit 8 octets, nombres entre 0 et 18.446.744.073.709.551.615, ou entre -9.223.372.036.854.775.808 et +9.223.372.036.854.775.807).

La mémoire peut se compter en kibioctets (anglais: kibibytes) (1 KiB = 1024 B), mébioctets (anglais: mebibyte) (1 MiB = 1024 KiB = 1.048.576 B), gibioctets (anglais: gibibyte) (1 GiB = 1024 MiB = 1.073.741.824 B). Une page de texte prend typiquement entre 1 et 2 KiB; le texte de la bible tient entre 4 et 5 MiB. [2]

Un ordinateur est typiquement livré avec juste assez de mémoire vive pour faire tourner confortablement le système du jour. En 2003, le système du jour est Windows XP ou Mac OS X ou Linux avec une interface graphique KDE 3, et la bonne quantité de RAM est 256 MiB. Une utilisation allégée se satisfera de moins (128 MiB voire moins avec des efforts), une utilisation intensive nécessitera plus (512 MiB et davantage).

Pertinence: savoir combien de place prennent des données est important pour évaluer la taille et le prix des supports à acheter, des lignes sur lesquelles faire transiter ces données, etc. Comprendre le fonctionnement du système peut permettre d'éviter des gâchis coûteux (comme un plantage dû à un manque de ressources), en évitant des opérations inutiles (transfert de très gros fichiers sur un réseau lent qui sera saturé plutôt que sur un disque), ou en achetant à l'avance des ressources nécessaires (RAM, disque dur).

1.3 Architecture virtualisée

Un ordinateur moderne correctement programmé peut exécuter plusieurs programmes à la fois. On dit alors qu'il est multitâche (anglais: multitasking), chaque programme différent étant une tâche (anglais: task) [3].

Pour simplifier de nombreux problèmes de programmation, y compris la gestion du multitâche, les ordinateurs à usage général modernes permettent d'écrire des programmes comme si chaque programme s'exécutait sur son propre ordinateur rien qu'à lui, isolé des autres, une machine virtuelle (anglais: virtual machine). on dit que le processeur et la mémoire sont virtualisés (anglais: virtualized). Un tel ordinateur virtuel s'appelle un processus (anglais: process).

Un programme spécial, le noyau (anglais: kernel) sert à maintenir cette illusion. Il utilise un mode de fonctionnement spécial du processeur, où sont disponibles des instructions inaccessibles aux autres programmes; ce mode spécial est appelé mode noyau (anglais: kernel mode) par opposition au mode utilisateur (anglais: user mode).

Pertinence: les problèmes en mode noyau (par exemple, utilisation de matériels mal reconnus) peuvent complètement planter la machine. Les problèmes en mode utilisateur peuvent rendre certains processus non fonctionnels, pendant que les autres processus continueront à tourner; dans ce dernier cas, il sera souvent possible de relancer les calculs voire de récupérer les résultats intermédiaires des programmes plantés.

Note: sur les systèmes modernes comme Linux (et tous les Unix), Windows NT/2000/XP, ou MacOS X (qui fonctionne en fait avec un Unix), l'isolation entre les processus est bien assurée. Ce n'était pas le cas sur les systèmes Windows 95/98/ME, MacOS 9, et de nombreux systèmes plus ancien (MS-DOS, Windows 3, MacOS 6/7/8), où une erreur sur un processus normal pouvait planter tout le système.

1.4 Persistence

La mémoire d'un ordinateur est typiquement effacée à chaque fois que l'ordinateur est éteint ou plante. Pour que les données persistent (anglais: to persist) à travers les extinctions et les plantages, il faut effectuer des opérations d'entrées-sorties sur une mémoire persistente (typiquement un disque dur (anglais: hard disk)) [4]. On parle aussi de mémoire de masse (anglais: mass memory, mass storage) parce qu'elle peut typiquement contenir beaucoup plus de données que la mémoire vive.

Cette mémoire de masse est typiquement divisée en fichiers, pour que des processus indépendants puissent travailler sur des données indépendantes (fichiers différents) ou des données partagées (fichiers identiques). Typiquement, un fichier est vu comme une longue suite d'octets. Un fichier est identifié par son un nom qui est une chaîne de caractère (anglais: character string). Il peut aussi selon le système posséder des attributs (anglais: attributes) qui définissent typiquement la date de dernière modification, le nom de l'utilisateur qui possède le fichier, etc.

Les fichiers sont typiquement classés dans un hiérarchie de répertoires (anglais: directories). Un caractère spécial ('/' sous Linux et les autres Unix, '\' ou optionnellement '/' sous Windows ou MS-DOS, ':' sous les anciens Mac OS et l'interface utilisateur de Mac OS X) sert de délimiteur (anglais: delimiter) pour séparer dans le nom du fichier le nom de la suite de répertoires où il se trouve (anglais: dirname) du nom de base (anglais: basename) du fichier.

Pertinence: Les données qui persistent entre deux lancement d'un processus sont les données sur le disque. C'est sur ces données qu'il faut agir, pendant qu'aucun processus ne les utilise activement, pour corriger des fautes qui surgissent d'un lancement à l'autre. Ce sont aussi ces données qu'il faut surveiller et protéger par une sauvegarde (anglais: backup) régulière, pour éviter toute corruption par un processus erroné, un plantage matériel, ou autre événement catastrophique.

Note: Sous Windows, les fichiers peuvent être sur l'une de plusieurs unités de disque (anglais: disk units), comme indiqué par une lettre et deux points. Sous Linux, tous les fichiers sont visibles sous la même hiérarchie, et des hiérarchies de fichiers provenant d'autres partitions, d'autres disques, ou d'autres machines (via NFS) peuvent être montées (anglais: mounted) chacune sous un répertoire qui servira de point de montage (anglais: mounting point), grâce à la commande mount(8) (voir aussi la commande SUBST sous MS-DOS). Sous Linux, on peut explorer les fichiers disponibles avec le navigateur konqueror, ou avec des commandes comme cd, pwd, ls(1), cp(1), mv(1), ln(1) [5].

1.5 Multiplexage des ressources

Les programmes utilisateurs partagent le même processeur et la même mémoire, ayant chacun son tour une tranche de temps (anglais: time slice) durant laquelle il s'exécute pendant que les autres sont en attente. Ils partagent aussi la même mémoire de masse, chaque disque étant divisé en des grossières partitions (anglais: partitions), et chaque partition pouvant abriter un système de fichiers (anglais: filesystem), lui-même subdivisé en de nombreux fichiers et répertoires avec leurs attributs.

Le noyau assure que les ressources (anglais: resources) du matériel (anglais: hardware) sont ainsi disponibles pour chaque processus du système. On dit qu'il multiplexe (anglais: to multiplex) les ressources. [6]

Dans le cas où il n'y a pas assez de puissance processeur pour effectuer toutes les tâches avant que l'utilisateur s'en aperçoive, on sentira le système ralentir; d'éventuelles requêtes en provenances du réseau pourront ne pas être traitées. Solution: acheter un ordinateur plus puissant, ou être plus économe en puissance. Dans le cas où il n'y a pas assez de mémoire vive réelle, le noyau pourra utiliser une partie de la mémoire de masse comme une extension (très lente) de la mémoire vive virtuelle, grâce à des partitions ou des fichiers d'échange (anglais: swap) à configurer à l'avance ou au dernier moment.

Pertinence: grâce à ce multiplexage, il n'y a presque plus à se soucier des ressources individuelles de chaque processus, mais seulement des ressources globales du système. Il faut néanmoins parfois surveiller le niveau des ressources et comprendre quels processus occupent trop de ressources (avec les commandes free(1), top(1), ps(1), pidof(8), lsof(8), fuser(8)) et parfois tuer le processus gênant (avec les commandes kill(1), killall(1)). L'interface graphique ksysguard) permet de faire tout cela. Attention que chaque système de fichiers peut déborder indépendamment des autres, ce qui peut être un plus (si cela permet à certains services de survivre à un débordement qui en fait planter d'autres; typiquement, les utilisateurs sont sur une partition à part, sur un serveur les logs aussi, etc.), ou un moins (davantage de plantages potentiels à gérer).

1.6 Appels systèmes

Pour effectuer des entrées-sorties réelles (lecture ou écriture de fichier, communication avec l'utilisateur) ou virtuelles (communication avec d'autres processus), les processus doivent passer par le noyau; pour cela ils utilisent des séquences d'instructions spéciales constituant des appels systèmes (anglais: system call). Le noyau se charge des vraies entrées-sorties, et de la communication entre processus.

Les appels systèmes sont documentés dans la section 2 du manuel de l'utilisateur [7] [8] Des appels systèmes typiques sont read(2) et write(2), qui permettent de transmettre des données entre les entités gérées par le noyau et la mémoire du processus courant.

Pertinence: toutes les communications entre un processus et d'autres processus ou le monde extérieur passent par le noyau. Il est ainsi possible de voir ce qu'un processus fait, d'intercepter ses communications, etc., avec des commandes comme ps(1), lsof(8), strace(1), etc. C'est très utile pour diagnostiquer les erreurs. [9]

Note: Contrairement à d'autres systèmes, le noyau Linux ne se soucie que de faire un travail limité de manière fiable et robuste. Il est « bête et méchant »: les données qu'il manipule ne sont pour lui que des zéros et des uns sans signification particulière, en dehors des paramètres de ses appels systèmes en tant que tels. Charge aux processus de rendre les données intelligibles aux utilisateurs.

1.7 Droits d'accès

Le noyau gère un certain nombre d'utilisateurs [10].

Des utilisateurs spéciaux existent qui ont des droits d'administration sur l'ensemble du système ou sur certains sous-systèmes logiciels limités. Sous Linux, l'utilisateur dont l'UID est 0, traditionnellement appelé root, possède tous les droits d'administration. On dit aussi qu'il s'agit d'un super-utilisateur (anglais: super-user) [11]

Le noyau vérifie à chaque appel système que le processus appelant fait une opération correcte et que l'utilisateur qui a lancé le processus possède les droits d'accès (anglais: access rights) nécessaires pour l'opération indiquée.

Le système maintient une séparation stricte entre ses propres données et celles des processus. Il peut ainsi continuer à tourner et à effectuer ces vérifications sans être affecté par d'éventuelles erreurs ou tentatives de sabotage par les processus.

On peut inspecter les droits d'utilisateur du processus actuel avec la commande id(1), ou encore whoami(1) et groups(1), voire who am i.

Pertinence: il faut savoir gérer les droits d'accès, pour faire attention que les processus qui sont censés tournés ne voient pas leurs requêtes refusées par le noyau. Pour empêcher et détecter rapidement les erreurs, il est utile se séparer strictement les programmes avec des utilisateurs différents pour des services différents aussi bien que utilisateurs humains différents. Enfin, pour des raisons de sécurité, il faut veiller à ce qu'il n'y ait pas de trou de sécurité (anglais: security hole) qui permette à un utilisateur mal-intentionné voire à un intrus d'obtenir des droits d'accès qu'il ne devrait pas avoir.

Note: Pour les administrateurs avancés, Linux dispose

1.8 Niveaux d'abstraction

On peut concevoir le système à de multiples niveaux d'abstraction.

Le noyau parle au matériel (anglais: hardware), et gère des processus.

Chaque processus voit le monde que lui présente le noyau et exécute une activité propre. Pour interpréter les données de ce monde, il intègre des bibliothèques (anglais: libraries) qui gèrent des conventions de codage.

Certains processus tournent en tâche de fond et fournissent des services (anglais: services) (tel que l'affichage graphique, la connexion à distance, l'impression de documents). On les appelle des démons (anglais: daemons). Certaines bibliothèques gèrent implicitement l'appel aux démons adéquats.

Parfois, des processus normaux et des démons coopèrent pour faire émerger un comportement cohérent. On parle alors d'environnement (anglais: environment). (Exemple: l'environnement de bureau graphique KDE).

C'est la tâche de l'intégrateur (anglais: integrator) de faire en sorte que sa distribution (anglais: distribution) de logiciels forme un ensemble cohérent qui fournisse aux utilisateurs un environnement stable.

Pertinence: Si vous voulez modifier le système pour le réparer ou l'améliorer, il faut comprendre à quel niveau agir. À un niveau trop haut ou trop bas, le problème est trop abstrait ou trop complexe, les moyens de le décrire sont trop inadéquats, et les moyens d'agir trop chargés de détails pas assez précis.

2 Le petit monde de Linux

Comprendre Linux proprement dit, c'est le comprendre au niveau d'abstraction des processus, ce qu'un processus voit, qui lui est fourni d'une part par le noyau, et d'autre part par les conventions standards universellement respectées par tous les processus et présentes dans les bibliothèques standards, pour interagir via le système de fichiers et autres moyens de communication. Il est toujours temps ensuite de découvrir les niveaux d'abstraction supérieurs, fournis par divers services optionnels, par les outils de paquetage des distributions, par les environnement de bureau graphique, etc. Ces niveaux supérieurs ne pouvant pas tout contrôler et intercepter sur le système, ils doivent en fin de compte ne se fier principalement qu'aux invariants de cohérence offerts par ce niveau de base.

Notons qu'à ce niveau, Linux n'est qu'une variante d'Unix, tel que défini par la Single Unix Specification, qui remplace les normes et standards de fait précédents, comme POSIX, BSD et System V.

2.1 Le monde vu par un processus

Un processus possède de nombreux attributs, qui définissent sa vision du monde et la vision que les autres processus en ont. L'interface graphique ksysguard) (entre autres) permet d'inspecter visuellement la table des processus (anglais: process table). Les attributs d'un processus:

Quelques commandes pour inspecter les processus. On peut regarder les processus actifs avec top(1). On peut regarder l'état et autres propriétés d'un processus avec ps(1). On peut regarder les arbres des processus pères/fils avec pstree(1) ou ps x --forest. On peut regarder les appels systèmes d'un processus grâce à strace(1). On peut regarder les fichiers ouverts par un processus grâce à lsof(8). On peut regarder soi-même en allant dans /proc/$PID.

Pertinence: les attributs d'un processus définissent et limitent la façon dont il interagit avec le reste du monde, en bien comme en mal (erreurs). Le fait que la plupart de ces attributs sont hérités de processus père à fils limite aussi la façon dont les informations se propagent: il n'est pas habituellement possible d'échanger des droits d'accès, des descripteurs de fichiers, des variables d'environnement, etc., d'un processus à l'autre; pour se contacter, deux processus doivent donc ou bien faire partie d'un groupe de processus ayant un ancêtre commun qui les synchronise en leur fournissant les bons attributs hérités, ou bien utiliser le système de fichier ou les services réseaux, le client contactant le serveur via un chemin d'accès ou un port de communication bien identifié [23].

2.2 Conventions d'usage

2.2.1 Paramètres de lancement d'une commande

Quand on lance une nouvelle commande, on spécifie un certain nombre de paramètres explicites et implicites: le programme, la ligne de commande, les variables d'environnement sous présents explicitement dans l'appel système execve(2); les fichiers déjà ouverts et autres attributs et ressources sont hérités du processus père ou pas au moment de l'appel système fork(2) ou sa variante clone(2) précédent le exec. Lors de l'execve(2), la mémoire est remise à zéro (aucun mapping), puis de nouveaux mappings sont créés pour le programme, les données privées du processus et sa pile d'exécution. Le programme peut alors faire de nouveaux mappings (pour les bibliothèques partagées notamment, ou pour demander plus de mémoire), et lire ou mapper des fichiers de configuration, des fichiers de travail, etc.

Quand on lance un nouveau programme en exécutant les appels systèmes [24], le noyau va donc charger le programme indiqué et lui fournir:

2.2.2 Options

Le comportement des commandes peut souvent être modifié par un nombre plus ou moins grand d'options.

Par convention, ces options sont spécifiés parmi les arguments d'appel, et reconnus en ce qu'ils commencent par le caractère - [27] De nombreux programmes ont des options courtes, introduites par un seul caractère -, et nommées par un caractère, et que l'on peut regrouper: ainsi ls -as active les options -a et -s. Parfois, il existe aussi des options longues, introduites par deux caractères -, et nommées par un mot; ainsi la commande précédente est équivalente à ls --all --size. D'autres programmes n'acceptent que des options longues avec un seul -.

Le caractère - tout seul signifie souvent l'utilisation de l'entrée ou de la sortie standard (selon le contexte) comme fichier sur lequel la commande doit agir. Doublé -- il signifie souvent la fin des options du programme appelé, le reste étant des paramètres normaux pour ce programme, même s'ils commencent par - [28].

2.2.3 Configuration

Pour déterminer ce qu'elle va faire effectivement, une commande regardera sa configuration, par ordre de priorité décroissante:

ls(1) et grep(1) sont vos amis pour identifier les fichiers de configuration, ainsi que strings(1) sur le binaire ou strace(1), mais bien sûr commencez par man(1), et s'il n'est pas concluant, tentez rpm -qil ou dpkg -L.

2.2.4 Gestion des erreurs

La convention est qu'un processus écrira sur sa sortie standard d'erreur (descripteur de fichier numéro 2) des textes relatifs aux erreurs ou événements anormaux ayant lieu. Les démons (processus tournant en tâche de fond) pourront souvent utiliser la facilité syslog(3) (apropos syslog) pour le journal des événements anormaux rencontrés. La configuration par défaut de syslog va en général correspondre à stoquer des journaux des événements survenus dans /var/log, mais il est possible de filtrer ce journal et de le rediriger vers d'autres fichiers, voire une autre machine, etc.

En se terminant, chaque processus donne un code d'erreur, nombre compris entre 0 et 255. La convention est que le 0 indique que le programme s'est déroulé correctement, tandis qu'autre chose indique une erreur qui n'a pas pu être corrigée.

Dans un shell, le code d'erreur du dernier programme est disponible dans la variable $?.

2.3 L'arborescence des fichiers

Les fichiers sont organisés dans une structure de répertoires (anglais: directories) récursivement imbriqués les uns dans les autres, appelée système de fichier (anglais: filesystem). On parle aussi d'arborescence de fichiers ou de hiérarchie de fichiers.

2.3.1 Noms de fichiers

Le nom d'un fichier (anglais: filename) proprement dit est une chaîne de caractère ne comprenant pas ni le caractère nul (de code 0), ni le caractère barre de division (anglais: slash) '/'. Sur le système par fichier standard de Linux (ext2 ou ext3), les noms de fichiers sont limités à 255 caractères.

Sous Unix, traditionnellement, la différence entre minuscule et majuscule compte. Ceci vaut pour les noms de fichiers et donc aussi par conséquence pour les noms de programmes exécutables (qui sont des fichiers) [30]

Un chemin d'accès à un fichier (anglais: pathname) (ou nom de fichier) est une chaîne de caractère formé de noms de fichiers séparés par des slashes '/'. Le fichier spécifié est obtenu en entrant successivement dans chacun des répertoires nommé par un composant du chemin d'accès jusqu'à arriver au dernier composant, qui est le nom du fichier désigné.

Si le chemin d'accès commence par un slash, alors il est dit être absolu (anglais: absolute), et commence à partir du répertoire racine. Sinon, il est dit être relatif, et commence à partir du répertoire de travail courant du processus actuel.

Au cours de la traversée d'un chemin d'accès, les noms de fichiers '.' et '..' font toujours référence au répertoire actuel et au répertoire père du répertoire actuel [31]

2.3.2 Liens durs et liens symboliques

D'autres fichiers sont des liens durs (anglais: hard links, hardlinks), de façon que plusieurs noms de fichiers correspondent à un même fichier réel, avec le même contenu et les mêmes attributs. Toute modification du fichier via un de ses noms sera visible sous chacun de ses autres noms, jusqu'à ce que le liens soit éventuellement brisé. Les fichiers de même lien dur sont identifiés par leur numéro d'inode, visible avec ls -li [32] Un fichier ne disparaît vraiment du disque que lorsque le dernier lien est supprimé. On ne peut faire de lien dur que vers un fichier de la même partition.

On peut lire le nombre de liens durs vers un fichier avec la commande ls -l. Notez qu'un répertoire a toujours de nombreux liens, au moins deux, puisque chaque parent est lié à son fils et réciproquement. On ne peut toutefois pas faire de lien dur sur un répertoire autrement que par une telle relation père-fils [33].

Il existe une autre sorte de liens. Certains fichiers sont des liens symboliques (anglais: symbolic links, symlinks) qui pointent vers un chemin d'accès (absolu ou relatif). Quand le noyau voit un tel lien, il remplace toute tentative d'accès à ce lien par une tentative d'accès au chemin désigné [34]

Les liens symboliques servent très souvent, pour préserver des chemin d'accès connus aux fichiers malgré le fait que l'arborescence réelle a été déplacée [35]. Ainsi, les liens symboliques permettent de conserver des chemins d'accès logique (anglais: logical) à chaque fichier.

Les liens durs, eux, servent à partager des données devant être accessible depuis un nombre indéterminé d'entrées de répertoire. De tels fichiers partagés sont souvent gardés en lecture seule après leur création initiale. Un exemple connu d'utilisation de liens durs est pour la gestion de groupes de discussion avec multipostage comme USENET (voir le serveur innd). Une autre application utile est pour le développement de versions concurrentes d'un même logiciel: on pourra ainsi partager les fichiers sources qui n'ont pas changé entre les multiples arborescences d'un logiciel dont on maintient simultanément plusieurs versions (dernière version stable connue, nouvelle version stable en provenance d'amont, version de développement en amont, version localement modifiée, etc.) [36].

2.3.3 Droits d'accès des fichiers

Chaque fichier a des droits d'accès déterminant qui a le droit d'effectuer quelles opérations sur le fichier. chgrp(1). root peut utiliser chown(1).

chmod(1)

rwx setuid setgid sticky [37]

Droits en octal.

Truc: rendre répertoires et exécutables accessibles à tous sans changer les autres droits: chmod -R a+X foo

Un paramètre spécial du processus actuel, disponible via la commande shell interne umask (qui utilise l'appel système umask(2)), détermine les droits d'accès qui seront refusés sur les fichiers créés. Le umask est noté avec la syntaxe numérique octale du chmod. Traditionnellement, le umask est mis à 022 pour que seul l'utilisateur actuel puisse modifier ses propres fichiers. Il peut être mis à 002 si le groupe actuel ne contient que l'utilisateur lui-même et des personnes de confiance sur le projet dont on modifie les fichiers. Il pourra être mis à 077 pour être paranoïaque et peu partageux vis-à-vis des autres utilisateurs. etc.

Par delà les droits d'accès unix traditionnels tels que décrits ci-dessus, certains systèmes de fichiers fournissent des droits supplémentaires. Par exemple, le système de fichier ext2 ou ext3 de Linux offre des attributs accessibles avec les commandes lsattr(1) et chattr(1).

Traditionnellement, quand on crée un utilisateur normal, on lui crée un répertoire personnel ou répertoire maison (anglais: home directory), (normalement répertorié dans le fichier passwd(5). Ce répertoire appartiendra au dit utilisateur, et il pourra ainsi y faire ce qu'il veut, sans être embêté par d'autres utilisateurs. Par convention, le répertoire actuellement considéré comme maison et connu via la variable d'environnement HOME.

2.3.4 Organisation conventionnelle du système de fichiers

Grâce aux techniques respectives des points de montage [38] et des liens symboliques [39], l'organisation du système de fichier (anglais: filesystem layout) est logique (anglais: logical) plutôt que physique (anglais: physical). C'est-à-dire que ce qui compte pour déterminer le chemin d'accès à un fichier est la structure logique de l'intention dans laquelle existe le fichier, plutôt que la structure physique du disque sur lequel est stoqué le fichier.

Pour le standard, plus ou moins respecté par toutes les distributions modernes, voir le FHS.

Fichiers systèmes: les répertoires /bin, /lib, /sbin, /usr, contiennent des fichiers des programmes gérés par votre distribution; le système ne modifie pas ces fichiers en temps normal, sauf quand vous installez de nouveaux paquets. /usr est lui-même divisé en de nombreux répertoires et sous-répertoires.

Fichiers de travail: Le répertoire /var contient les fichiers de travail persistents des services installés. Le répertoire /tmp (et/ou parfois aussi /var/tmp) contient les fichiers temporaires du système, qui n'ont pas besoin de survivre à un redémarrage des programmes ou services qui les utilisent.

Fichiers de configuration du système: sous Unix, les fichiers de configuration sont généralement dans /etc, et les distributions modernes s'y tiennent assez bien pour les paquets qu'elles gèrent. Si vous installez des logiciels d'une autre provenance, vous pourrez aussi en avoir dans /opt/etc, /usr/local/etc, /var/qmail, etc.

Fichiers magiques: Parmi les ressources multiplexées par le système, il y a les périphériques (anglais: devices) connectés au système (écran, clavier, souris, son, réseau, disque, imprimante, scanner, etc.), chacun géré par un gestionnaire de périphérique (anglais: device driver) approprié. Sous Linux, ces périphériques sont souvent vus comme des fichiers spéciaux, « magiques », dans le répertoire /dev. D'autres fichiers « magiques » pour configurer le système sont dans /proc (allez donc y faire un tour avec cd, ls et cat) voire dans certaines versions du système dans /sys. Seul l'administrateur a normalement le droit d'agir directement sur ces fichiers spéciaux.

Fichiers utilisateurs: /root contient souvent le répertoire utilisateur de root, tandis que les autres utilisateurs sont souvent mis dans /home (en général le répertoire par défaut où la distribution les met; certains préfèrent /users ou quand il y a beaucoup d'utilisateurs, une arborescence logique en-dessous de /home ou /users). Le répertoire utilisateur de l'utilisateur courant est dans la variable d'environnement HOME, que les shells modernes abrègent souvent en ~. Les fichiers de configuration personnels de chaque utilisateur sont dans son répertoire personnel avec un nom commençant par un point (par exemple ~/.bashrc pour le programme bash(1)).

Autres: /opt ou /usr/local contiennent typiquement des programmes qui ne sont pas gérés par la distribution, mais par un autre système de paquetage, voire installés manuellement par l'administrateur. /mnt est souvent utilisé pour des montages temporaires. Pour le reste, votre imagination est la seule limite!

2.3.5 Trouver des fichiers

La documentation peut aider à les trouver.

2.4 Les services en réseau

Ce qui a fait le succès d'UNIX en général et de Linux en particulier a toujours été leur intégration aux réseaux utilisant les protocoles de l'Internet (TCP/IP).

Linux gère aussi d'autres types de réseau et de services (par exemple, AppleTalk grâce au logiciel netatalk(8) ou Novell grâce à marsnwe(8)), mais ceux qui valent le plus la peine d'être connus sont les réseaux IP. [41]

À introduire dans cette section:

Pour une discussion de ce qui fait qu'UNIX est historiquement particulièrement adapté aux services en réseau, voir la discussion sur la notion de terminal.

2.5 L'interface graphique X

Architecture en couches: serveur X, window manager, desktop environment (GNOME, KDE, XFCE), bibliothèques de fonctions, applications, etc.

transparence réseau (anglais: network transparency): les programmes sont censés pouvoir s'exécuter de n'importe quelle machine vers n'importe quelle machine.

export DISPLAY=:0
export DISPLAY=machine:0

Authentification: xhost(1x), xauth(1x). Sur certaines distributions, la configuration par défaut du serveur X n'écoute pas sur le réseau, et vous devez modifier ce point-là à la main.

Pour davantage de sécurité, tunnel ssh ou IPSEC, etc.

De nombreuses complications font que la transparence réseau marche mal dès qu'on veut faire plus que d'afficher des données ou que l'on veut utiliser l'une de diverses extensions au protocole X, voire des protocoles qui agissent à côté de X: le son, l'accès direct à l'écran, les fontes, etc., sont chacun source de problèmes de configuration "intéressants".

Un résumé de l'état de l'art: Open Source Desktop Technology Road Map.

2.6 Initialisation du système

Finalement pour comprendre Linux, il faut comprendre comment Linux démarre. Pour tous les détails, lire le HOWTO adéquat...

Démarrage de la machine: la ROM initialise le matériel, puis cherche un "secteur d'amorce" sur une disquette, un disque dur, le réseau, etc.

Le secteur d'amorce va charger le reste du programme d'amorce du système. Pour Linux, il s'agit typiquement de GRUB ou de LILO, qu'il ira chercher à tel numéro sur tel disque, tel que spécifié lors de l'installation de GRUB ou de LILO.

Le programme d'amorce offre éventuellement un menu, et en fin de compte, décide de charger tel noyau avec tel paramètre, à moins qu'il ne donne la main au programme d'amorce d'un autre système (par exemple, au secteur d'amorce d'un disque contenant Windows).

Le programme d'amorce cherche le noyau à l'endroit indiqué. GRUB lit le système de fichier et retrouve le noyau d'après son nom de fichier; LILO est plus bas niveau et reconstitue le noyau en cherchant tel et tel secteur du disque; LILO doit donc être réinstallé à chaque fois que le noyau est modifié.

Une fois chargé par le programme d'amorce, le noyau prend la main. Le programme d'amorce peut donner au noyau des paramètres de lancement ainsi qu'un "disque de démarrage" virtuel à charger en mémoire contenant des programmes pour démarrer le système.

Le noyau lance le processus init(8) sur son disque de démarrage. S'il s'agit d'un disque de démarrage virtuel, il va généralement donner la main au programme init du disque réel après avoir chargé les gestionnaires de périphériques adéquats.

Pour la suite, voir la documentation de init(8), sa vie son œuvre, et ses fichiers de démarrage.

La configuration de démarrage selon la convention System V, et ses runlevels.

3 Réflexes de base pour survivre
3.1 Survivre avec l'interface graphique

C'est difficile à décrire seulement qu'avec des mots. Suivez le cours.

Le processus qui parle au matériel: le serveur X. Il accepte des connexions de clients en local ou sur le réseau, qui communiquent en utilisant le protocole X11R6 avec diverses extensions [42]. Lancer le serveur X quand il n'est pas lancé automatiquement: startx [43].

Attention:

3.2 Savoir survivre avec la ligne de commande

Pour lire le manuel d'une commande nommée toto: man toto. Autres façons d'obtenir de l'aide (parfois): toto -h ou toto -\? ou toto --help ou toto -help ou simplement toto.

Si toto est un programme interactif, essayer au cours du programme la commande help ou les touches: h ? H Ctrl-H Alt-H.

Pour sortir d'une commande, essayer: q Q Ctrl-Q Ctrl-D

Pour interrompre une commande, essayer: Ctrl-C Ctrl-\ Ctrl-Z.

Votre shell est sans doute bash(1) (mais je recommande de changer pour zsh(1) si vous le pouvez, en utilisant chsh(8)), donc pour avoir de l'aide à propos du shell: man bash.

Pour lire son courrier électronique: mutt

Pour avoir la liste des fichiers: ls

Pour connaître l'effet d'une commande: type commande

Pour lister le contenu d'un fichier: less fichier

Pour changer de répertoire: cd

Pour quitter le shell: exit ou parfois logout ou C-d

Autres commandes courantes: zsh cp mv ln rm mkdir rmdir echo cat gzip tar grep cut ps

3.3 Utiliser l'aide

Une distribution Linux est vient typiquement avec une documentation en-ligne extensive, sans parler des sites sur internet (voir la section "pour en savoir plus"). Il faut juste savoir où et comment regarder.

Sous KDE, ouvrez le programme khelpcenter, et naviguez.

Avec la ligne de commande, vous disposez de la commande man(1) pour lire les pages de manuel, de la commande info(1) (ou de emacs(1)) pour lire les pages info, de lynx(1) (ou links(1) ou w3m(1)) pour lire les fichiers html, de la commande less(1) pour lire les fichiers textes, ou zless(1) s'ils sont comprimés avec gzip(1). Les fichiers dvi peuvent être lus avec xdvi(1) (ou advi(1) s'ils sont actifs); les fichiers ps ou pdf peuvent être lus avec gv(1x), kghostview(1) ou ggv(1); les fichiers pdf peuvent aussi être lus avec xpdf(1) ou acroread(1) (logiciel exclusif).

Les pages de manuel sont dans /usr/man et dans les autres répertoires de votre $MANPATH, mais vous pouvez les consulter directement avec un nom de commande, ou chercher un mot dans l'index avec man -k motclef. Les pages info(1) sont dans /usr/info et dans votre $INFOPATH. De nombreux fichiers de documentation en mode texte ou en html se trouvent selon la distribution dans /usr/doc ou /usr/share/doc; c'est là, dans un répertoire HOWTO qu'on trouve souvent les notables documents du Linux Documentation Projet qui expliquent comment résoudre divers problèmes ciblés quand on débute avec Linux, (et en fait même quand on connaît déjà Linux mais qu'on débute avec le domaine du problème en question).

3.4 Pour en savoir plus

Les pages de manuel (disponibles graphiquement avec khelpcenter, ou par la ligne de commande avec man(1)) sont une excellente référence, mais ne sont pas orientées vers la résolution de problèmes spécifiques. Heureusement, il existe de très nombreux documents sur Internet écrits par des techniciens ayant déjà affronté les mêmes problèmes que vous, et qui vous permettront de survivre.

3.5 Apprendre à utiliser un éditeur

Si vous devenez un utilisateur expérimenté, vous devrez apprendre à utiliser un éditeur de fichiers textes.

Parmi les plus simples, il y a en mode graphique l'éditeur kwrite qui suffit pour les besoins de tous les jours.

L'éditeur visuel le plus universellement disponible sous tous les systèmes UNIX est vi(1); pour pouvoir se sortir de cas extrêmes où on démarre sur une disquette ou un système autrement restreint, il est donc utile de savoir survivre sous vi. Toutefois, en-dehors de cette utilisation, vi lui-même est à éviter. Il existe par contre une version très améliorée et extensible de vi: vim(1) (y compris la version intégrée à KDE, kvim(1)), qui est un éditeur tout à fait décent; je conseille ceux qui veulent apprendre vi à lire le tutoriel de vim et à se faire une cheat sheet (demander à Google).

La mère de tous les éditeurs, véritable système d'exploitation à lui tout seul, écrit et extensible dans son propre dialecte de Lisp, c'est GNU EMACS. Emacs se décline dans sa version officielle de la FSF, ou dans la version rivale XEmacs. Dotés de nombreux modules pour faciliter le développement de programmes dans de très nombreux langages, ou pour lire son courrier, naviguer sur le web, se connecter à des bases de données, etc. Là encore, commencez par utiliser le tutoriel et par imprimer la reference card. Vous trouverez aussi dans ces notes de cours, à la section sur le shell en mode EMACS, les quelques commandes les plus usuelles.

Notez que vim, emacs et xemacs sont tous trois disponibles sous Windows comme sous MacOS X, et que les talents que vous acquerrez à les maîtriser pourront donc être aussi mis à profit sur vos autres plateformes de travail.

3.6 Habitudes élémentaires de précaution

Faites des sauvegardes régulières avec copie distante. Par exemple, j'utilise rsync(1) avec une clef SSH (créée par ssh-keygen(1)).

Quand vous changez un fichier de configuration important, dont le dysfonctionnement pourrait vous empêcher de plus vous connecter, gardez ouverte une console avec un shell tournant sous l'ancienne configuration jusqu'à avoir vérifié que la nouvelle configuration tourne. De même, ne changez rien au démarrage de votre machine sans avoir une disquette ou un CD de démarrage à votre disposition. Effectuez vos changements majeurs de distribution sous chroot(8) et ne redémarrez qu'après avoir bien testé.

Ai-je bien dit qu'il fallait faire des sauvegardes régulières avec copie distante?

Mettez vos fichiers de configuration importants sur un serveur CVS ou équivalent pour pouvoir récupérer les anciennes versions qui marchaient et consulter les différences qui auront déclenché un dysfonctionnement. Je ne suis pas tout à fait au courant de l'offre, mais on me dit qu'il y a mieux de nos jours: j'utilise encore CVS, mais de nos jours, Subversion fait tout ce que fait CVS en mieux et plus robuste et de façon quasi-compatible, et il existe de nombreux logiciels qui proposent des approches plus intéressantes, dont Arch, Code*ville, DARCS, Meta-CVS, monotone, OpenCM. Affaire à suivre.

Au cas où je n'aurais pas été assez clair, faites des sauvegardes régulières avec copie distante.

Oh, j'allais oublier la règle la plus importante: faites des sauvegardes régulières avec copie distante.

3.7 Apprendre à programmer

La différence entre un programmeur et un utilisateur, c'est que le programmeur sait qu'il n'y a pas de différence entre programmation et utilisation. Vous apprendrez donc à programmer, que vous en soyiez conscients ou pas. Si vous devenez utilisateur expérimenté, autant vous y mettre consciemment. Quelques soient les langages que vous apprendrez, le meilleur moyen, après avoir parcouru des documents introductifs, est lire des exemples simples en ayant le manuel sous la main. Repérez donc des programmes simples utilisant le langage que vous apprenez, et lisez-les, exécutez-les pas-à-pas, etc.

Sur l'esprit général dans lequel le code linux existant est écrit, voir par exemple TAOUP; cela dit, il y a d'autres approches ou d'autres vues sur la programmation, et si la programmation est un sujet qui vous passionne, vous trouverez plus et mieux sur des sites adéquats.

3.7.1 Programmation shell

Pour survivre dans la vie de tous les jours, il faut connaître un minimum votre shell: bash, ou celui que je recommande, zsh. Si vous administrez une machine, vous aurez souvent besoin d'écrire des petits shell scripts, ou du moins de modifier des scripts existant pour les adapter à vos besoins.

Pour écrire des shells script portables, il faut aussi savoir se limiter aux fonctionnalités du shell POSIX de base (soupir!). Mais pour vous-mêmes, n'hésitez pas à utiliser toute la puissance de votre shell; quoique si vous avez vraiment besoin de puissance, choisissez un meilleur langage ci-dessous.

Vous voudrez aussi sans doute configurer votre shell pour le rendre plus convivial; outre la documentation de votre shell (sur votre machine ou le site officiel) et les fichiers d'exemples qui vont avec, il y a des sites comme d'information comme shelldorado [44].

3.7.2 Programmation de scripts

En administrant des machines, vous voudrez souvent écrire des petits programmes, des scripts, qui automatiseront vos tâches, lieront ensembles les programmes disparates que vous utiliserez, etc. Plusieurs solutions s'offrent à vous:

3.7.3 Langages de programmation sérieux

Dès que vous commencez à écrire un programme sérieux (disons, plus de cinq mille lignes), alors fuyez les langages de scripts, et optez pour un vrai langage de programmation, conçu pour faire de la programmation propre, efficace, bien structurée, robuste, expressive, etc. Voici les langages les plus adaptés à la programmation sérieuse, qui offrent chacun à sa façon les paradigmes de programmation fonctionnel, objet et générique, avec en plus des spécifités propres:

Si vous vous tournez vers la programmation, il existe aussi de nombreux autres langages chacun avec ses dialectes, qui pourront vous ouvrir l'esprit vers de nouveaux horizons tout en vous permettant de faire de la programmation sérieuse: Haskell, Scheme, Mercury, Oz, etc. Il y a de très nombreux langages de programmation. Voir par exemple la page Programming Languages du wiki de TUNES.

3.7.4 Programmation système

Parfois, vous aurez besoin de descendre dans des couches relativement basses du système, ou du moins de comprendre ce qui s'y passe. Pour cela, il vous faudra apprendre un langage d'implantation système, même si dans la pratique, il est recommandé de ne s'en servir qu'avec parcimonie, et d'enrober les routines et bibliothèques écrites dans ces langages pour utilisation dans un langage sérieux de haut niveau comme vu précédemment.

Si ces langages systèmes, de bas niveau, permettent d'obtenir des performances supérieures dans des micro-benchmarks, dans des programmes de taille raisonnable, les langages de haut niveau les rattrapent en permettant d'optimiser plus facilement l'organisation des structures de données; de plus, le cas échéant, il est toujours possible d'employer après profilage (anglais: profiling) (voir man -k prof) un langage de bas niveau juste pour les quelques boucles fines (anglais: tight loops) qui occupent la majeure partie du temps de vos programmes.

3.7.5 Programmation ennuyeuse

Il est des langages de programmation qui offrent de mauvais compromis techniques, mais qui sont néanmoins répandus, pour des raisons économico-politiques. Ils sont aussi disponibles sous Linux.

4 Le shell et ses amis
4.1 Shell 101

4.1.1 La notion de shell

Dans la terminologie UNIX, un shell est un logiciel qui offre à l'utilisateur une interface vers l'ensemble du système. Littéralement, le mot signifie coquille, et indique bien que c'est le composant le plus extérieur du système, directement en contact avec l'utilisateur, par opposition au noyau qui est au cœur du système et aux applications entre les deux.

Si on peut considérer que l'interface graphique GNOME ou KDE constitue un shell, et si l'éditeur EMACS est effectivement utilisé par certains comme un shell dans tous les sens du termes, on réserve l'appellation de shell au sens strict à des programmes conçus pour fonctionner dans un terminal en interprétant les commandes de l'utilisateur ligne-à-ligne, et en lançant les programmes spécifiés.

Le shell est le sel et la terre de l'utilisateur UNIX expérimenté:

Sur le sujet de ligne de commande par opposition à l'interface graphique, voir l'article célèbre de Neal Stephenson In the beginning was the command line (aussi ici ou voire sur le site original).

4.1.2 L'offre disponible

Il existe de nombreux shells: ash(1), bash(1), csh(1), dash(1), posh(1), ksh(1), pdksh(1), rc(1), tcsh(1), zsh(1), sans parler de shells spéciaux pour systèmes de secours comme busybox(1), kiss(1) ou sash(1), variantes que je ne traiterai pas davantage ici [45].

Le standard POSIX, repris par la norme SUS, définit ce que sait faire le shell standard de base /bin/sh. La plupart des shells reprennent ce standard et l'étendent avec des fonctionnalités spécifiques. GNU bash(1) est le premier parmi ceux-là, et à l'époque où tous les marchands d'UNIX exclusifs livraient des shells antiques et bogués jusqu'à la moëlle, il s'est imposé comme standard de fait chez les utilisateurs expérimentés; il est aujourd'hui le plus répandu dans le monde Linux, et un standard officiel du Linux Standard Base. Aussi, dans la plupart des distributions, /bin/sh est un lien symbolique ou dur vers /bin/bash (qui détecte qu'il a été appelé comme sh et adapte son comportement en correspondance pour être le plus compatible possible). Cela au point que parfois, des programmes censés marcher sur n'importe quel UNIX dépendent en fait de fonctionnalités spécifiques à bash(1), ce qui est en général une erreur non intentionnelle de la part du développeur.

csh(1) et son successeur tcsh(1) utilisent une syntaxe notablement différente du shell POSIX, et qui se veut plus proche du langage C. Durant l'époque précédent l'émergence de Linux et la victoire populaire de bash(1), ils ont eu un certain succès, mais il n'y a aucune particulière raison de s'y intéresser de nos jours, à part pour déboguer un rare script issu de temps anciens.

ksh(1) se veut le nouveau standard officiel parmi les systèmes UNIX exclusifs, et possède de nombreuses extensions en faisant un langage bien plus raisonnable que sh pour l'écriture de scripts. Cependant, comme il a longtemps été un logiciel exclusif, il n'a jamais été très répandu, et n'a finalement rien de spécial à offrir, puisque pour tout script avancé, on lui préférera de loin perl(1) ou un autre langage plus avancé, cependant qu'en terme de fonctionnalités interactives, il pêche devant bash(1) ou zsh(1). Pendant que ksh(1) n'était pas libre, une version libre rivale pdksh(1) a été développée, qui n'est pas forcément compatible à 100% avec le ksh(1) officiel.

ash(1) ou dash(1) est la version BSD du shell POSIX, qui colle au plus près à la norme, avec quelques rares extensions. À quoi bon s'y restreindre? À être sûr que vos shell-scripts sont portables. Shell minimal inventé juste pour vérifier la portabilité des scripts: posh(1).

rc(1), issu du système expérimental Plan9, se veut un redesign mieux conçu du shell, de même que Plan9 était un redesign mieux conçu d'Unix (mais qui, n'étant pas libre, a manqué son occasion de percer). Incompatible, pauvre en fonctionnalités, il a fait quelques émules, mais n'est pas si extraordinaire que ça.

Mon préféré est zsh(1), le « shell ultime » qui reprend les meilleures idées de sh(1), bash(1), tcsh(1) et ksh(1), et possède même des modes de compatibilité sh, bash(1), et ksh(1) (et aussi csh mais de façon incomplète). Mais surtout, il possède un grand nombre de fonctionnalités, y compris un mode de complétion programmable, un éditeur intégré, et il est très très configurable et très très extensible avec des modules dynamiquement chargés. Pourquoi s'en priver?

On peut changer le shell par défaut d'un utilisateur avec la commande chsh(8) [46]. Les administrateurs téméraires pourront éditer directement le /etc/passwd [47]. Il faut se reloguer pour que la modification prenne effet.

4.1.3 Quel shell apprendre?

Je vous enseignerai ici le bash(1), qui est le standard sous Linux, tout en précisant parfois dans quelques notes les différences pour le shell POSIX sh et le « shell ultime » zsh(1).

Pour apprendre votre shell en détail, je vous invite toutefois à consulter la page de manuel, à regarder la configuration par défaut sur votre système, à lire les fichiers d'exemples livrés avec le shell, à visionner les sources de shell-scripts utilisant votre shell.

4.1.4 Principe de base du shell

Le shell offre une interface en ligne de commande (anglais: command line): un interacteur permet à l'utilisateur d'éditer une ligne de texte qui spécifie une commande à exécuter.

L'interacteur se reconnaît généralement à l'invite (anglais: prompt) qu'il affiche avant chaque commande. On peut typiquement personnaliser cette invite (grâce à une variable d'environnement nommée PS1 ou PROMPT), de façon à afficher le répertoire courant, l'heure, le nom de l'utilisateur ou de la machine actuelle, ou toute autre information pertinente [48].

Quand on confirme la commande en appuyant sur la touche entrée, le shell lit la ligne qu'il analyse comme un petit programme qu'il exécute. Dans le cas habituel, le plus simple, le programme est une commande simple suivie d'arguments; le shell lance alors ladite commande avec les arguments spécifiés. Ainsi, la commande ls -l /bin appellera typiquement la commande externe ls avec comme arguments l'option -l d'une part et le nom de répertoire /bin d'autre part.

4.1.5 Vos premières commandes

Vous pouvez essayer les commandes suivantes, et utiliser en parallèle konqueror pour essayer de visualiser l'effet de ces commandes:

echo 'Hello, world!'   # affiche des informations
kwrite toto.txt        # édite un fichier
pwd         # affiche le répertoire actuel
ls          # affiche les fichiers dans le répertoire actuel
cd ..       # change le répertoire actuel au répertoire père
pwd         # affiche le répertoire actuel (après cette modification)
ls          # affiche les fichiers dans ce nouveau répertoire
ls -l       # affiche les même fichiers avec davantage d'information
ls -la ~    # le contenu de votre répertoire personnel avec ses fichiers cachés
ls -ld .    # informations sur le répertoire actuel lui-même
ls -F       # ajoute des symboles 
cd /        # va dans le répertoire racine
ls
cd bin      # répertoire des programmes de base du système UNIX
pwd
ls
cd /usr/bin # répertoire avec de nombreux programmes
pwd
ls
cd          # dans quel répertoire vous transporte cette commande?
pwd         # dans votre répertoire personnel!
ls

4.2 Interaction avec le Shell

4.2.1 Édition de ligne avec le shell

Les shells modernes comme bash(1) tcsh(1) zsh(1) gèrent directement l'interaction avec le terminal, et vous offrent de nombreuses facilités pour vous simplifier la vie. Ils peuvent traditionnellement fonctionner selon deux modes, le mode emacs ou le mode vi, dont le comportement imite chacun celui d'un des deux éditeurs traditionnels les plus populaires du monde Unix. Je vous enseignerai le mode emacs, qui est le mode par défaut; lisez le manuel pour le mode vi.

Pour bash(1), l'éditeur intégré s'appelle readline(3) et est configurable via le fichier ~/.inputrc (voir man 1 bash ou man 3 readline). Sous zsh(1), l'éditeur intégré s'appelle zle est avec la commande bindkey à appeler depuis votre ~/.zshrc ou interactivement (voir man 1 zshzle). Notez que de dans le monde UNIX, de nombreux autres programmes interactif, en mode texte ou en mode graphique, utilisent des combinaisons de touches directement inspirées de EMACS, voire utilisent directement readline(3).

Note: par convention du monde EMACS, on écrit C-r pour Contrôle-r, c'est-à-dire laisser enfoncer la touche modificatrice Ctrl, puis la touche R, relâcher le R puis la touche Ctrl. On écrit M-x pour Méta-x, la touche Méta étant souvent celle avec l'étiquette Alt sur les claviers de PC. Dans un terminal, M-x est équivalent à la séquence d'échappement ESC x. La touche d'échappement ESC est aussi équivalente à C-[.

4.2.2 Le shell en mode EMACS

Déplacement sur la ligne actuelle: flèche gauche ou C-b (back) pour caractère précédent, flèche droite ou C-f (forward) pour caractère suivant. Prochain mot: M-f, précédent mot: C-b. Début de ligne avec Home ou C-a, fin de ligne avec End ou C-e.

Effacement: Delete ou C-d pour détruire le caractère suivant, BackSpace pour détruire le caractère précédent [49]. C-u pour effacer toute la ligne, ou C-w pour effacer le mot précédent (non disponibles sous EMACS proprement dit). Effacer la fin de la ligne: C-k

Copier/Couper-Coller: C-y pour récupérer le groupe de caractères dernièrement effacé ou sélectionné. C-SPC pour marquer le début d'une zone à sélectionner, M-w pour sélectionner la zone depuis le marqueur précédent. (ces derniers non disponibles sous bash(1).)

Récupérer les commandes précédentes: flèche haute ou C-p (previous) pour la précédente, flèche basse ou C-n (next) pour la suivante. Recherche en arrière avec C-r ou en avant avec C-s.

Annulation: Annuler la recherche ou toute autre opération spéciale en cours: C-g. Annuler la ligne actuelle ou interrompre une commande: C-c, très pratique si on ne sait plus où on en est question guillemets et parenthèses. Sous emacs(1) ou zsh(1), C-x u pour annuler une modification durant l'édition, plusieurs fois pour en annuler plus (non disponible sous bash(1)).

Entrer un caractère spécial directement: C-v. Vous aurez peut-être en plus à le mettre entre guillemets. Notez que sous EMACS proprement dit, C-v sert à passer à la page suivante cependant que M-v va à la page précédente, et il faut utiliser C-q pour l'effet ci-dessus.

4.2.3 La complétion

Parce qu'ils passent du temps sur leur ligne de commande, les utilisateurs d'UNIX ont de nombreux trucs pour accélérer la frappe. Outre l'édition de ligne et son couper-coller, un truc important est la completion: sous un shell moderne, utilisez la touche Tab pour compléter le nom d'un fichier ou d'une variable que vous avez commencé à taper.

Quand il y a plusieurs fins possibles, le shell complète jusqu'à l'endroit où il faut choisir. Vous pouvez avoir la liste des choix disponibles sous bash(1), en appuyant sur ESC ESC ou Tab. Sous zsh(1), la touche C-d en fin de ligne permet de voir la liste des choix disponibles [50] et la touche Tab propose chacun son tour chacun des choix possibles.

Sous zsh(1), la complétion est particulièrement puissante, et est de plus programmable; vous pouvez ainsi inclure dans votre configuration zsh des complétions adaptées spécifiquement à chacun des programmes que vous utilisez, plutôt que toujours des noms de fichiers.

4.2.4 Le terminal sans éditeur

Les antiques shells standards d'UNIX sh(1) csh(1) ou vieux ksh(1), ainsi que la plupart des programmes conçus pour être invoqués depuis le shell, n'ont pas d'édition de ligne. À défaut de mieux, le gestionnaire de terminal inclus dans le noyau peut gérer pour ces programmes qui ne veulent pas s'en soucier une édition de ligne rudimentaire.

Dans son mode par défaut, le noyau n'enverra au programme lecteur le texte saisi qu'après réception de la touche entrée; cela lui permet de gérer entre autres choses l'effacement arrière (BackSpace) et l'annulation de la ligne (C-u), ainsi que le signal de fin de fichier (C-d en début de ligne). Le noyau enverra un signal d'interruption (kill -INT) au processus courant si on appuie sur la touche C-c, et un signal de fin prématurée (kill -QUIT) si on appuie sur la touche C-\, ou encore un signal d'arrêt momentané (kill -STOP) si on appuie sur la touche C-z (voir la section job control ci-dessous).

On peut ainsi signaler aux programmes qui lisent leur entrée sur l'entrée standard que cette entrée est terminée en leur envoyant une fin de fichier. Si un programme tarde trop à répondre, on peut l'arrêter définitivement avec C-c ou momentanément avec C-z (et le reprendre avec la commande fg).

Pour plus de détails sur les façons d'interagir avec le terminal, voir la section sur le terminal.

4.3 Commandes simples

4.3.1 Invocation d'une commande

La syntaxe la plus simple pour une commande est une liste constituée par le nom de la commande suivi par ses arguments, les composants de la liste étant séparés par un ou plusieurs espacements.

Exemple: ls -l /bin lancera la commande ls avec les arguments -l et /bin.

Si la commande est parmi la liste des commandes internes au shell (anglais: shell built-in commands) telle que documentée dans le manuel, ou une fonction définie par l'utilisateur alors ladite commande sera exécutée.

Sinon, le shell créera un nouveau processus qui exécutera une commande externe. Si le nom de la commande est un chemin d'accès (absolu ou relatif) spécifiant un répertoire, alors il spécifiera le programme à exécuter (utiliser ./foo pour préciser le répertoire actuel). Si ce nom ne comporte pas de répertoire, alors le shell ira chercher dans chacun des répertoires définis dans la variable d'environnement PATH si un programme de ce nom existe, et exécutera le premier [51]. Si aucun programme n'est trouvé dans le $PATH, ou que l'utilisateur ne possède pas les droits d'accès en exécution sur ledit programme, alors le shell renvoie une erreur [52].

4.3.2 Commandes pour s'en sortir avec les fichiers

Les commandes suivantes permettent de manipuler les fichiers à partir du shell textuel. Pour des cas simples, cela n'apporte rien par rapport à l'interface graphique; par contre, l'interface textuelle pourra être automatisée et fiabilisée.

4.3.3 Conventions d'appel pour les commandes

Une commande prend un nom de commande suivi de paramètres, dont des options. [55]

Les options conventionnellement généralement par un caractère '-'. De nombreuses commandes acceptent de grouper plusieurs options simples derrière un seul '-': cp -ax /foo /bar au lieu de cp -a -x /foo /bar, ou tar -zxvf foo.tar.gz au lieu de tar -z -x -v -f foo.tar.gz. De nombreuses commandes ont des options avec un nom long, et la convention aujourd'hui dominante est que de telles options doivent être introduites par deux caractères '-': cp --help. De nombreux programmes suivent la convention supplémentaire selon laquelle le caractère '+' est employé pour désactiver l'option activée avec le caractère '-'. Certaines options sont suivies d'un chemin d'accès à un fichier, d'un nombre ou d'un autre paramètre.

La seule façon fiable de savoir comment fonctionne une commande, c'est de lire sa documentation: man nom_de_commande. Les commandes internes (anglais: builtin commands) de votre shell sont décrites dans la page de manuel dudit shell: man bash ou man zshbuiltins.

Le shell lui-même possède des options (très nombreuses dans le cas de zsh(1)), documentées dans le manuel. À fins d'inspection (pour débogage notamment), on peut appeler le shell avec l'option -x pour tracer les commandes. Ou on peut l'activer durant l'exécution avec set -x ou la désactiver avec set +x. Sous bash(1), on préférera shopt pour changer les options. Sous zsh(1), on préférera setopt. Notez sous zsh(1) l'option LOCAL_OPTIONS pour ne changer des options qu'à l'intérieur de la fonction actuelle.

4.4 Expansion des commandes par le shell

Principe supplémentaire: avant d'exécuter votre commande comme un petit programme, le shell va d'abord procéder à une expansion de la commande, remplaçant textuellement diverses parties de la commande par le résultat de calculs simples, déclenchés par la présence de caractères spéciaux (anglais: special characters) dans la commande originale. Le processus d'expansion est décrit en détail dans la section EXPANSION de la page de manuel de bash(1), ou dans la page zshexpn(1) en ce qui concerne zsh(1). Cette expansion permet de faire du shell et de ses amis, les programmes qu'il appelle, un véritable petit langage de programmation.

4.4.1 Variables

environnement. variables exportées ou pas. expansion. La différence entre minuscule et majuscule compte dans les noms de variables (comme dans les noms de fichiers).

echo $HOME
FOO=bar
echo $FOO
env
export FOO
env
FOOBAR=baz
echo $FOOBAR
echo ${FOO}BAR

Nombreuses options pour l'expansion des variables: valeur par défaut, extraction de sous-chaînes, etc.

man bash section EXPANSIONS; man zshexpn, et dans man zshbuiltins voir typeset.

zsh(1), comme ksh(1), possède aussi des variables listes contenant une liste de chaînes de caractères. Extrêmement utile pour des fonctions et scripts.

Variables spéciales du shell: man bash section Shell Variables; man zshparam.

4.4.2 Échappements et guillemets

Quotes:

A='Hello,  world'
echo $A
echo '$A'
zsh# echo $=A
Erreur, à terminer avec Ctrl-C# A=l'ivrogne
Explication: le quote débute une phrase; le shell ne terminera la lecture de la ligne actuelle que quand le quote ' sera refermé, ou qu'il aura été interrompu (par Ctrl-C).

Double quotes:

echo "$A"
echo "L'ivrogne"

Backslash:

echo L\'ivrogne
A="Salut \"toi\""
echo \$A
echo "\$A=$A"
echo '\$A=$A'
echo "\\\$A=\$A"
echo '$A='$A
echo '$A='"'$A'"
echo "\$A=$(perl -e 'print(join(" ",map(quotemeta,@ARGV)))' -- "$A")"

to split or not to split. "$@" vs "$*".

4.4.3 Chemins d'accès

Chemins absolus ou relatifs si vous êtes l'utilisateur cepl1 dans votre répertoire personnel /home/cepl1, alors ces chemins correspondent tous au même fichier:

Notez que le tilde ~ et la variable $HOME sont "expansés" (anglais: expanded) par le shell et ne sont pas vus par la commande exécutée, cependant que les répertoires spéciaux . et .. sont gérés par le noyau.

4.4.4 Globbing

Les divers shells réagissent diversement dans le cas où rien ne correspond, selon qu'ils soient interactifs ou pas, selon leurs options, etc. Essayez avec ls -l foo*bar*baz.

Avec zsh(1), on peut paramétrer le résultat avec des options du shell. zsh(1): setopt NULL_GLOB, man zshoptions unsetopt NULL_GLOB. zsh(1) possède aussi un système d'options pour qu'un pattern ne corresponde qu'à des fichiers d'un certain type (fichiers véritables, liens symboliques, répertoires, fichiers exécutables, etc.).

Exercice: utiliser le globbing pour enlever des fichiers de backup, déplacer des fichiers image, etc.

4.4.5 Backquote

Le langage de programmation du shell est très rudimentaire, et le shell a souvent besoin de récupérer le résultat de commandes externes pour pouvoir l'utiliser dans la suite du contrôle des commandes à exécuter. Pour cela, il y a le mécanisme des backquotes `commande...` par lequel une commande spécifiée entre backquotes est exécutée, et sa sortie standard lue par le shell et lorsque la commande termine, ce résultat est employé en remplacement des backquotes.

Exemple: pour aller dans le répertoire des modules du noyau courant, utilisez cd /lib/modules/`uname -r`.

$( ... ) Même effet que les backquotes, mais moins sujet à problème, notamment pour les imbriquer. N'existe pas dans les shells les plus antiques.

zsh(1): créer un fichier temporaire avec =( ... ). Utile pour les commandes qui tiennent absolument à travailler avec un fichier plutôt qu'avec un pipe.

4.4.6 Calculs arithmétiques

$(( 1 + 2 * 3 )) (ancienne notation: $[ ... ])

Incrémenter un compteur: (( i = i + 1 )) (aussi: let "i = i + 1" ou i=$[ $i + 1 ] ou en shell POSIX de base, i=`expr $i + 1`.)

4.4.7 Brace expansion

tcsh(1), et à sa suite bash(1), ksh(1), zsh(1), a une fonctionnalité par laquelle les métacaractères accolades (anglais: braces) '{' et '}' servent à délimiter des choix qui seront expansés par le shell en toutes les combinaisons possibles dédits choix. Essayer les commandes suivantes:

echo a{b,c,d}e
echo FOO{0,1,2,3,4}{a,b,c,d}
echo {bar{0,1,2},{baz,quux}{3,4,5}}.html
Exercice: prévoyez avant de l'exécuter ce que va faire la commande suivante: echo x{{0,1,2,3,4,5,6,7,8,9},{1,2,3,4,5,6,7,8,9}{0,1,2,3,4,5,6,7,8,9}}

zsh(1) possède une extension fort utile à ce système: S'il n'y a pas de virgules, zsh(1) reconnaît que les choix possibles sont des caractères spécifiés comme dans un motif de glob entre crochets. Essayez: print -l 0x{0-9a-f}. Exercice: avec zsh(1), générez avec les accolades des noms de fichier appelés image$x.gif pour toutes les valeurs de $x entre 0 à 255. (Solution [56])

4.4.8 Alias

seulement pour des raccourcis claviers de commandes fréquentes (ou arguments fréquents avec les alias globaux de zsh) dont on veut spécifiquement qu'ils aient un comportement différent sous la frappe et dans un programme. Exemple typique, alias cp='cp -i' ; alias mv='mv -i' ; alias rm='rm -i' Pour tous les autres usages, utiliser des fonctions.

4.5 Commandes élaborées

Par opposition aux commandes simples.

4.5.1 Redirection

Redirections de fichiers: << < > >> >& >>& >! 2> 2>&1 /dev/null

Sous Unix, le moyen typique pour combiner des commandes est d'utiliser des tuyaux (anglais: pipes) avec la syntaxe commande1... | commande2... pour rediriger la sortie de l'un dans l'entrée de l'autre. Exemples typiques: examiner le contenu d'une arborescence avec un pager décent: ls -lR | less

Rediriger en même temps la sortie standard et la sortie d'erreur:

commande arguments >& foo
commande arguments > foo 2>&1
commande arguments |& traitement sortie
commande arguments 2>&1 | traitement sortie

Partage des variables ou non:

ls --sort=time | head -1
ls -l --sort=time | read A B C D E F G H ; echo $E $H

Exemples: wc, less

4.5.2 Regroupement de commandes

Séquences de commande avec ;. Exemple: sleep 3 ; echo -e '\007'

Regroupement de commandes avec { }. Exemple: echo "1 2 3" | { read A B C ; echo $A }

Commandes dans un sous-shell avec ( ). Exemple: (cd /usr/src/linux ; make). Différence: les variables et autres attributs du processus modifiés dans le sous-shell n'affecteront pas le shell principal

Commandes en tâche de fond avec &. Exemple: xterm & Pour certaines applications (notamment graphiques), on préférera parfois utiliser setsid(8) accompagné de redirections vers /dev/null (null(4)) ou vers un fichier de logs. Exemple: setsid firefox < /dev/null >& /dev/null

Neutralisation de commandes avec : (commande qui ne fait rien, avec succès, et que l'on peut rediriger) ou avec # (commentaires, ne change pas $?, n'est pas redirigé).

4.5.3 Structure

Rappel de la convention pour la gestion des erreur: un processus se termine avec un code de retour qui est 0 en cas de succès (vrai) ou différent de zéro en cas d'échec (faux). La variable $? permet de récupérer le résultat de la dernière commande. Ainsi, exécution conditionnelle avec if ...; then ... ; else ... ; fi, ou encore avec commande1... && commande2... (conjonction - continuer si vrai) ou commande1... || commande2... (disjonction - continuer si faux), ! commande... (négation - changer vrai en faux et vice-versa). Souvent utilisation du programme test(1) ou de l'équivalent interne au shell, [, pour divers tests.

Par exemple, pour éviter que le /etc/zshrc s'exécute quand l'utilisateur possède sa propre configuration, utiliser if [ -f ${ZDOTDIR:-$HOME}/.zshrc ] ; then return ; fi

Boucles avec for, while.

for i in *.txt ; do cp $i ${i}.bak ; done
i=0 ; while (( i < 20 )) ; do echo $i ; let i='i+1' ; done

Programmation par cas et pattern matching avec case ... esac.

4.5.4 Fonctions et Scripts

Dès que vous réutilisez des commandes identiques ou fortement similaires plus de trois fois, il devient utile d'écrire une fonction qui vous simplifiera dorénavant la tâche, et dont la formulation vous aidera à bien comprendre ce que vous faites.

function foo () {
  for i ; do echo "ARG: $i" ; done
}

Pratique: : sert à afficher des informations ssi on est en mode debug (set -x).

4.5.5 Programmation Shell Avancée

Parallélisme avec & (et éventuellement $!).

Tuyaux nommés avec mknod foo p.

zsh(1): coproc.

Ne faites pas comme moi, arrêtez-vous avant de devenir fou, et utilisez un vrai langage de programmation.

Pertinence: savoir que c'est possible, savoir ce qui est « facile » sous Unix, et ce qui ne l'est pas.

4.6 Trucs à connaître

4.6.1 Job control

job control: C-z, fg, bg, kill, kill -CONT %1, kill -STOP, &, $!, etc. C-c, C-\. Pour tous les détails, voir la page de manuel du shell.

4.6.2 Noms de fichiers cachés

Par convention, les fichiers dont le nom commence par un point (anglais: dot) . sont cachés par défaut par l'interface utilisateur. On peut les visualiser tout de même avec l'option -a de ls(1), en cliquant au bon endroit dans kfm ou gmc, etc.

Ces fichiers cachés sont typiquement employés pour les fichiers de configuration personnalisée des divers programmes (essayez donc ls -a ~), des fichiers temporaires ou automatiquement générés, et autres données ancillaires qui ne concernent pas directement l'utilisateur typique (.cvsignore pour CVS, .depend dans beaucoup de Makefile, .AppleDouble pour netatalk, etc.).

Interaction avec le globbing: * .* (zsh(1): setopt GLOB_DOTS) Attention! Sous sh(1) et bash(1), le filtre .* va laisser passer . et .. les répertoires actuel et précédent; Sous bash, utiliser .??* en conjonction possible avec .[^.] pour tous les fichiers cachés sauf ces deux-là.

Personnellement, je déteste le fait de tout mettre en vrac dans ~ (ou même dans /etc), et les fichiers que je personnalise à la main, je les mets dans des sous-répertoire de ~/etc (ou /etc, avec un lien symbolique depuis l'endroit où le programme va le chercher vers l'endroit où je préfère le stoquer. Un avantage supplémentaire est de pouvoir mettre mes fichiers de configuration sous contrôle d'un programme de gestion de versions multiples (j'utilise le très-répandu cvs(1)), ce qui est très pratique à de nombreux égards (archivage avec historique, partage entre nombreuses machines, détection de bugs et récupération d'une version qui marche).

4.6.3 Noms de fichiers ressemblant à des options

Clash entre options et nom de fichier. Parfois, un nom de fichier peut commencer par un tiret, que ce soit de manière intentionnelle ou pas (exemple: echo 2 > -i ou n'importe quel copier-coller d'un texte avec un >) et si c'est intentionnel, avec une intention bonne ou mauvaise. Dans ces cas, comment faire pour donner un tel fichier à traiter à une commande? Réponse: sur des commandes modernes, en indiquant la fin des options avec -- comme avec rm -- -i. Sur des commandes plus anciennes, en donnant un chemin avec répertoire pour que le tiret ne soit pas en premier: rm ./-i.

4.6.4 Noms de fichiers difficiles à reproduire

Utiliser des quotes. Dans les quotes, utiliser éventuellement un $(echo -e '\033') (code octal).

Utiliser la complétion.

Utiliser le globbing.

4.7 Configuration du shell

Votre shell lira des fichiers de configuration légèrement différents selon qu'il décide ou non d'être un shell de démarrage (anglais: login shell) d'une part et un shell interactif (anglais: interactive) d'autre part.

Il est un shell de démarrage s'il est invoqué par la commande login(8) [57]. On peut forcer un shell bash(1) ou zsh(1) (mais pas le shell POSIX de base) à être de démarrage avec l'option -l. On peut forcer zsh(1) à ne pas l'être avec l'option +l. S'il est de démarrage, le shell lira un fichier de configuration supplémentaire, dans le répertoire système /etc puis chez l'utilisateur. Pour sh il s'agit du .profile, pour bash(1) il s'agit du .bash_profile, pour zsh(1) il s'agit du .zprofile.

Un shell sera interactif s'il détecte que son entrée standard est reliée à un terminal (par opposition à être lié à un fichier ou un tuyau) [58] . On peut forcer un shell à être interactif avec l'option -i, et on peut forcer zsh(1) à ne pas l'être avec l'option +i. S'il est interactif, le shell lira un fichier de configuration supplémentaire, dans le répertoire système /etc puis chez l'utilisateur: pour bash(1) il s'agit du .bashrc, pour zsh(1) il s'agit du .zshrc, pour sh il n'y a pas de tel fichier. Dans ce fichier de ressources pour shell interactif, on configurera

Note sur fichiers de configuration global du shell: ils sont le Mal, de ce genre de bonnes intentions dont l'enfer est pavé. À défaut de les effacer, il est bon de les désactiver sélectivement en mettant à leur début une commande comme [ -f "$HOME/.bashrc" ] && return pour le /etc/bash.bashrc ou sinon d'utiliser l'évaluation conditionnelle pour ne pas polluer la configuration d'un utilisateur avec des commandes indésirables et parfois irréversibles.

4.8 Quelques amis du shell

4.8.1 Petits utilitaires

sort(1) pour trier des données (sort -u est utile pour éviter les doublons).

cut(1), head(1) et tail(1) pour extraire des données.

Exercice: identifier tous les programmes utilisés comme shell de login. (Indice [61])(Solution [62])

pr(1) pour formatter une sortie sur plusieurs colonnes. Exemple: cat /etc/passwd | cut -f 1 -d: | pr -5

printf(1) pour formatter des messages.

find(1) Pour pouvoir les intégrer chacun à une URL présentable, vous voulez extraire les noms de fichiers (par opposition à répertoire) du répertoire courant en les débarassant du disgracieux préfixe ./ — Comment vous y prendrez-vous? (Indice [63])(Solution [64])

xargs(1) [65] Exemple: find /usr/include -type f | xargs grep "malloc" cherchera quel fichier d'entête C définit la fonction malloc(3) (dans ce cas là, la page de manuel aurait pu vous le dire).

Pour faire des calculs plus compliqués, intensifs ou conviviaux que ne sait le faire votre shell: expr(1), dc(1), bc(1), rpncalc(1) (pour une vrai calculatrice scientifique HP avec interface graphique, utilisez x48), voire clisp(1) (pour un vrai langage de programmation dynamique).

Utiles pour certains scripts dans des shells antiques: basename(1), dirname(1).

Informations diverses sur le système: hostname(1), uname(1), whoami(1).

4.8.2 Contrôler la sortie

Redirection vers /dev/null ou un fichier. Souvent, option -o pour utiliser un fichier plutôt que la sortie standard (ou l'imprimante, pour certains programmes produisant du PostScript). Souvent, le pseudo-nom-de-fichier - signifie la sortie standard plutôt qu'un fichier.

less(1) (version largement améliorée du more(1) des UNIX propriétaires): permet d'aller en arrière, ainsi que de faire de la recherche d'expressions régulières: touche / pour la recherche, ? pour recherche en arrière, n (next) ou / RET pour répéter la dernière recherche. Utiliser h pour l'aide, q pour quitter [66].

tee(1)

mail(1) pour envoyer du courrier depuis la ligne de commande [67]. Pour l'interface interactive, ou pour envoyer des attachements, préférer mutt(1). ).

logger(1), syslog(2), syslog(3), etc.

4.8.3 Contrôler l'entrée

Redirection depuis /dev/null ou un fichier. Souvent une option pour utiliser un fichier plutôt que l'entrée standard. Souvent le pseudo-nom-de-fichier - sert à signifier l'entrée standard plutôt qu'un fichier.

commande << END suivi de nombreuses lignes puis d'une ligne contenant END (ou le marqueur choisi quelqu'il soit). C'est très utile dans un script, où on appelle (anglais: here document) le document incis grâce à cette redirection. En interactif plutôt que dans un script, c'est moins utile, puisqu'on on peut utiliser C-d plutôt que <<END pour envoyer une fin de fichier à un programme. Toutefois, le <<END permet de mettre des variables à expanser dans le texte; si on veut spécifiquement éviter une telle expansion, utiliser des guillemets autour du code: <<'END'.

echo 'foo bar baz' | commande

yes(1)

Sous zsh(1), commande <<< 'foo bar baz' est un équivalent plus court.

4.8.4 Gérer la divergence des fichiers

cmp(1) diff(1) diff3(1) patch(1) xdelta(1)

rsync(1) unison(1)

cvs(1) et consorts. (De nos jours utiliser plutôt svn(1) que cvs(1); voir la section "Habitudes élémentaires de précaution") )

4.8.5 Comprimer et Archiver

L'utilitaire standard pour comprimer des fichiers est gzip(1) [68]. Vous pouvez décomprimer un fichier avec gunzip(1) ou l'envoyer dans un tuyau grâce à zcat(1). Pour vous éviter des tuyaux dans tous les sens, voir aussi zless(1), zgrep(1), zdiff(1), etc.

Dans le monde UNIX et donc aussi Linux, le standard de fait en matière d'archivage est la commande tar(1), dont les fichiers sont conventionnellement nommés avec le suffixe .tar [69].

Les commandes les plus usuelles pour manipuler des fichiers tar sont:

Note de politesse et de prudence quant aux archives tar et autres: une archive peut contenir de nombreux fichiers, qui seront désarchivés dans le répertoire actuel. Ils pourront écraser des fichiers du répertoire actuel, et/ou il pourra être difficile de repérer tous les fichiers de l'archive (y compris les fichiers cachés en .*) pour les effacer le moment venu. Aussi, il est poli, en créant une archive, de mettre tous les fichiers en-dessous d'un unique sous-répertoire dont le nom est bien distingué, de façon à épargner toute mauvaise manœuvre à celui qui recevra l'archive. Et il est prudent ou bien de vérifier (avec l'option t de tar, combinée à less(1)) que l'archive se comporte selon vos attentes, ou bien de créer un nouveau sous-répertoire dans lequel extraire bien à part le contenu de l'archive, que son créateur ait été poli ou non.

Encrypter vos archives pour qu'elles ne tombent pas en de mauvaises mains: gpg(1) — faites très attention à vos clefs, maillon faible du système. Et faites attention que dès que vous êtes un peu prudent avec la technique, l'électronique est rarement le maillon faible d'une organisation humaine.

4.8.6 Vous connecter au réseau

ssh(1) pour lancer des commandes à distance. (gestion des clefs, rsh(1) si vraiment confiance, etc.)

netcat(1) pour connecter des commandes à des services réseau.

stunnel(1) et consorts pour faire du SSL.

4.8.7 Aide à l'écriture

dict(1), ispell(1), aspell(1).

fortunes(6) (considéré comme un jeu — man -k game).

4.9 Expressions régulières

Les expressions régulières (anglais: regular expressions) sont un moyen de définir des filtres permettant d'isoler ou d'exclure certains bouts de texte [71]. On les emploie pour faire de la recherche et du remplacement de texte dans des fichiers.

Pour apprendre les regexp: expreg, regexp, article53, regex2, node6, article.

La commande usuelle pour trouver du texte dans des fichiers est la commande grep(1). Elle possède plusieurs variantes: egrep(1), fgrep(1), pcregrep(1).

Exemple: en supposant que les élèves de la promotion 2004 aient un répertoire personnel sous /home/eleves/2004, on peut compter combien il y en a grâce à < /etc/passwd grep /home/eleves/2004/ | wc -l

Une autre commande utile (mais moins standard) est rename(1) qui sert à renommer des fichier avec des regexp de perl(1) (ou toutes autres commandes perl(1)).

sed(1), awk(1). perl(1), vrais langages. vi(1), emacs(1), éditeurs, etc.

Diverses versions subtilement incompatibles des regexp, entre grep(1), egrep(1), perl(1), pcregrep(1), vi(1), emacs(1), etc. AARRGGG! Ainsi, pour le remplacement \1 dans les anciens outils dont grep(1), mais $1 dans perl(1) (qui accepte aussi \1).

Standard de fait vers lequel tendent ceux qui évoluent: perlre(1). (notamment avec la bibliothèque pcre(7)perl-compatible regular expressions.) Cependant, perl(1) lui-même évolue, alors il y a et il y aura toujours des incompatibilités subtiles. Toutefois, le fond commun est là, qui ne change pas trop. Les incompatibilités sont sur les extensions et les détails subtils.

Attention au double niveau de citation et d'échappement quand on appelle perl(1) depuis un shell plutôt que d'écrire un perl-script.

perl -npe 's/foo/bar/g; s/baz/quux/g;'

Exercice: Repérer les occurrences du mot « attention » dans ce fichier texte. (Solution [72])

Exercice: supposons que vous avez oublié le nom du fichier où se trouve la base de donnée des utilisateurs, mais que vous vous souvenez qu'elle se trouve avec toute la configuration du système dans un fichier de /etc et que vous êtes l'utilisateur cepl. Utilisez grep(1) pour retrouver les fichiers où apparaît le mot cepl. (Solution [73])

Évaluer le nombre de lignes où apparaît le mot « foo » dans le fichier cepl-linux.html. (Indice [74])(Solution [75])

5 Applications disponibles sous Linux
5.1 Applicatifs les plus courants

Savoir lancer un applicatif depuis KDE: Ctrl-F2. Depuis GNOME, etc. Au pire, lancer depuis un shell dans un terminal (attention au &).

X: firefox(1), thunderbird(1), ooffice(1), qiv(1), texmacs(1), xchat(1), mplayer(1), ogle(1), xmms(1), xplaycd(1), ... [76]

petits outils X: xbiff(1), xzoom(1), xeyes(1), xroach(1).

GNOME: galeon(1), gimp(1), evolution(1), gcd(1), gaim(1), abiword(1)...

KDE: konqueror(1), kwrite(1), KOffice (kword(1), etc.), kontour(1), kroupware(1), kmail(1), kopete(1), k3b(1), juk(1), etc.

EMACS ou XEmacs: w3, gnus, terminal, shell...

terminal: mutt(1), links(1), lynx(1) ou w3m(1); cdtool(1), aumix(1), epic(1), etc.

ligne de commande: mailx(1), mix(1), mpg321(1), sox(1), ...

filtres mail: procmail(1), spamassassin(1), bogofilter(1), ...

Common-Lisp: clim, closure, ...

5.2 Quel type de documents produire?

Sortie finale. HTML, man page, info, PDF, PS (PostScript). Très bien pour les documents en lecture seule, sans plus de modifications, mais ne convient pas à la modification (sauf retouche très légère). Pour visionner du HTML, utilisez votre brouteur web habituel: konqueror(1), galeon(1), firefox(1), opera(1) (logiciel exclusif), etc. Pour visionner du PostScript ou du PDF, utiliser les dérivés ghostview(1): gv(1), ggv(1), kghostview(1), etc. Pour le PDF, essayez aussi xpdf(1), acroread(1) (logiciel exclusif), etc.

Traitement de texte. Concept standard avec OpenOffice, Gnome Office, KOffice, etc. Pour un usage plus avancé, essayez TeXmacs.

Textes Scientifiques: Le standard pour l'écriture de textes scientifiques est LaTeX, lui-même basé sur TeX. Prévu pour produire du Postscript ou du PDF: ps2pdf(1) vs pdflatex(1). Avec, on peut aussi faire du HTML: hevea(1), LaTeX2HTML(1), tex2page(1). Notez que si vous ne voulez pas programmer dans un langage abscons, je vous recommande l'outil graphique TeXmacs cité ci-dessus.

Documentation simplifiée. Il existe de nombreux systèmes de documentation facilement éditables et programmables, qui permettent d'obtenir toute une gamme de sorties, avec un système plus sympathique que LaTeX, quoiqu'avec moins de fonctionnalités pour les cas tordus. Voir par exemple reStructuredText, Scribe, et tant d'autres. (cl-typesetting?) Éviter texinfo(1), perlpod(1).

Images. JPG pour images lisses avec dégradés continus, comme une photo; légère perte de qualité mais pas trop grave. Bonne compression. PNG pour images très tranchées (texte et dessin sur fond blanc, etc.) MNG pour images animées. GIF: non! (mauvaise compression, brevets sur la compressions, features en moins, pas de différenciation facile entre GIF animés ou pas, etc.) — voir ci-dessous l'exercice sur le Burn All GIFs day. Images vectorielles: pas vraiment de standard; selon votre application.

5.3 Correspondance rapide Windows vers Linux

Windows a longtemps péché par l'absence d'un outil de ligne de commande digne de ce nom, avec l'exécrable COMMAND.COM de MS-DOS et le CMD.EXE de Windows NT. Pour ceux d'entre vous qui sont habitués à ces antiques lignes de commande sous Windows ou MSDOS, il existe des HOWTOs et pages webs donnant ces correspondances.

Correspondances entre commandes.

Notons qu'il est aussi possible d'installer sous Windows le sous-système Cygwin qui permet d'utiliser toutes les fonctionnalités de Linux ou presque, avec ses shells bash(1) ou zsh(1).

Enfin, notons que les toutes dernières versions de Windows (pour développeurs seulement) possèdent maintenant le fameux Monad Shell, dont la brillante conception devance celle des shells de Linux. Chapeau à Microsoft!

5.4 Correspondance rapide MacOS vers Linux

Pour ce qui est de l'UNIX sous-jacent à MacOS, il s'agit d'une variante de BSD nommée Darwin. Il y a un échange permanent de sources entre Darwin et les autres BSD. Voir la section suivante si vous êtes familiers avec la ligne de commande sous MacOS X.

5.5 Différences rapides entre BSD vers Linux

Les BSD sont l'autre grande famille de systèmes UNIX libres (ou pas forcément libres, d'ailleurs). Le principal du groupe est FreeBSD, mais il y a aussi NetBSD qui tente de tourner partout, et OpenBSD qui tente d'être aussi sécurisé que possible.

Les outils BSD sont souvent plus minimalistes que les outils GNU, n'ajoutant aux fonctionnalités standards que le strict nécessaire. Tandis que les outils GNU et autres programmes qui tournent au-dessus d'un noyau Linux forment un tout disparate, chacun étant censé fonctionner dans de nombreux systèmes et contextes différents, et l'ensemble étant intégré par des gens différents des développeurs, le noyau et les outils BSD proprement dit forment un tout intégré développé par des groupes de personnes maintenant la cohérence du tout. Au final, un système BSD de base aura légèrement moins de fonctionnalités qu'un système GNU/Linux de base, mais semblera plus simple, plus dépouillé, plus authentique; mais ces différences s'estompent après avoir installé tous les mêmes programmes que sous GNU/Linux pour ce qui est des outils destinés aux utilisateurs finaux.

5.6 Différences rapides entre Linux et les UNIX propriétaires

Sur un système UNIX de base, sh(1) n'a pas d'édition de ligne, mv(1) ne marche pas d'un file-system à l'autre, mkdir(1) n'a pas d'option -p, cp(1) n'a pas forcément d'option -a (mais -r -p), les versions de patch(1) et de diff(1) peuvent être obsolètes (quand elles sont disponibles), les bugs dans les outils de base n'ont jamais été corrigés, etc. Bref, il y a à peine de quoi survivre. Heureusement, on peut installer les outils GNU en remplacement des outils de base.

Par contre, les UNIX propriétaires offrent souvent (contre espèces sonnantes et trébuchantes) un matériel conçu spécialement pour fournir des serveurs robustes, des compilateurs optimisant donnant du code de qualité supérieure, un support technique garanti, etc. Toutefois, il est aussi possible d'acheter une licence pour un tel compilateur et l'utiliser sous Linux, et d'acheter le support technique sous Linux. Bref, il s'agit pour une entreprise d'une question économique. Pour un particulier, en général, il n'y a pas photo, et la familiarité des particuliers avec Linux contribue à abaisser le coût de Linux pour les entreprises.

6 Tout se complique
6.1 Disquettes, CD-ROMs, etc.

Les distributions récentes ont souvent un système d'automontage (par exemple avec automount(8)) ou de montage à la volée quand on clique au bon endroit. Sinon, on peut monter et démonter à la main avec mount(8) et umount(8) (mais il faut être root).

Pour utiliser plus simplement disquette formattée au format VFAT (utilisé par MSDOS et Windows, lu par tout le monde), il existe une interface accessible par tous les utilisateurs qui ont accès au lecteur de disquette (typiquement, en les mettant dans un groupe qui a accès à /dev/fd0): mtools(1), et ses commandes (mdir(1), mcopy(1), mdel(1), mcd(1), mren(1), mformat(1), etc.) qui mimiquent les commandes équivalentes sous DOS.

On peut formatter physiquement une disquette avec superformat(1) (ou avec son prédecesseur fdformat(8)). Pour mettre dessus un système de fichier, on peut utiliser mformat(1) pour le format VFAT, ou sinon mkfs(8) et ses variantes spécialisées (mkdosfs(8) pour le format VFAT, mke2fs(8) pour le ext2, etc.).

Pour les CD-ROMs et DVD-ROMs, on pourra utiliser k3b(1) et k9copy.

Pour plus d'information, voir les HOWTOs appropriés.

6.2 Les bibliothèques à liaison dynamiques

Pour partager des fonctionnalités entre de nombreux programmes, Linux possède comme tous les systèmes d'exploitation moderne un système de bibliothèques à liaison dynamique (anglais: Dynamic Link Libraries), aussi appelé système de bibliothèques partagées (anglais: Shared Libraries). Cela permet de ne pas gâcher de la mémoire en répliquant ces fonctionnalités dans chaque processus; cela permet aussi la mise à jour de ces fonctionnalités sans avoir à recompiler tous les programmes; cela permet enfin de charger dynamiquement des extensions et autres plugins compilées séparément des programmes qui les utilisent. Mais cela nécessite parfois un peu de maintenance.

Le processus normal:

On peut examiner les appels API qu'effectue un programme vers ses bibliothèques dynamiques grâce à l'utilitaire ltrace(1) [84].

API: cf. dlopen(3), documentation du format de fichier ELF, le Program-Library-HOWTO, etc.

Pertinence: si des bibliothèques partagées requises pour un programme ne sont pas présentes, ce programme ne fonctionnera pas. Il faudra les installer. Assurez-vous que les bibliothèques nécessaires sont bien disponibles dans /lib et /usr/lib [85]. Les distributions modernes gèrent automatiquement les dépendances entre les programmes qu'elles installent et leurs bibliothèques.

6.3 Gestion du temps

Pour lancer des processus à intervalles réguliers: cron(8). Pour machines non allumées en permanence, voir aussi anacron(8).

Lancer un processus une seule fois: at(8). Voire, sleep(1).

Agenda personnel, alarme de notification, etc.: il y a une offre diversifiée qui a beaucoup évolué.

Programme de base pour obtenir la date et l'heure: date(1) [86]. Changer la date et l'heure, pour l'administrateur seulement: option -s.

Temps universel vs timezones. lien symbolique /etc/localtime. TZ=Asia/Tokyo date.

Horloge système: hwclock(8). Temps universel ou non (option -u): Problème de partage avec Windows ou MacOS (!).

Temps réseau: protocole NTP, usage ponctuel avec ntpdate(1), démon ntp(1).

UNIX note le temps en seconde sur un entier signé 32 bits depuis début 1970 (l'année de la conception d'UNIX) [87]. Il n'y a donc pas de bug de l'an 2000, mais bug de l'an 2030 et quelques! Exercice: trouver l'instant précis de la fin du monde, à la seconde près. Hint: on pourra par exemple procéder par dichotomie, grâce à des commandes du genre date -u -d '1970-01-01 00:00:00 UTC'; mais il existe une solution plus simple encore [88].

Tricher sur l'heure pour un processus (bug de l'an 2000 ou 20xx, licence expirée, test): c'est possible en interceptant les appels d'API qui donnent l'heure, via $LD_PRELOAD [89] (au pire, il faudra modifier le binaire s'il est statiquement lié, en s'aidant de strace(1) et de gdb(1)).

API du noyau: gettimeofday(2), time(2), nanosleep(2), setitimer(2), etc. Cf. /usr/include/time.h et consorts, tels que listés dans les pages de manuel. Voir surtout la documentation de votre langage de programmation favori.

6.4 Les terminaux

6.4.1 Principe du terminal

Dans le pas-si-bon vieux temps, on accédait à ses machines via des terminaux reliés à la machine par une ligne série. Le terminal envoie à la machine ce que l'on tape au clavier sous forme du code ASCII des caractères tapés, et reçoit ce qu'il doit afficher de la même façon [90] [91]. Des séquences d'échappement (anglais: escape sequences) de plusieurs caractères comprenant des caractères de contrôle, sont employées pour obtenir des effets spéciaux; par exemple, les touches flèches de direction enverront chacune une séquence spécifique, tandis que l'ordinateur enverra aussi des séquences pour positionner le curseur dans la fenêtre, écrire en gras, changer de couleur, etc. [92]

Malgré la grande variété des terminaux, le principe lui-même est devenu un standard de fait, repris par tous les systèmes de type UNIX, et conservé même à l'heure des interfaces graphiques. S'il fallait faire le procès des terminaux, voici ce que je retiendrais.

Points négatifs:

Points positifs:

6.4.2 Configuration du terminal

Il existe de très nombreux types de terminaux différents, parfois subtilement différents, sans parler des types de liaisons différentes (câble série, modem, service télématique, services réseau, couche d'émulation, etc.) et des enchaînement de moyens de liaisons entre le terminal final et la machine effective qui envoie les ordres, sans parler des diverses options à configurer à chaque étape de tels enchaînements. Aussi, la configuration d'un terminal peut être extrêmement compliquée. Heureusement, les cas simples, comme par exemple se loguer sur la machine locale préconfigurée par un intégrateur compétent, marchent tout seuls sans effort.

Le type de terminal utilisé: echo $TERM [96].

La taille du terminal est dans $ROWS et $COLUMNS; si ce n'est pas fait automatiquement, on peut mettre ces variables à la bonne valeur avec eval $(/usr/bin/resize) [97].

Pour déterminer le nom du device auquel est connecté le programme actuel: tty(1). Sous bash(1): echo $tty. Sous zsh(1): echo $TTY.

Pour configurer la liaison série (réelle ou virtuelle) entre le terminal et l'ordinateur (du moins sur le tronçon géré par la machine actuelle), la commande stty(1) est votre amie. Par exemple, pour voir toute la configuration actuelle, stty -a.

Pour configurer la locale(1) de votre terminal, exportez les variables appropriées dans votre configuration shell. On changera typiquement LANG et LC_CTYPE ou bien LANG et LC_ALL. Quelques valeurs possibles pour la langue: fr_FR, de_DE, fr_LU, de_LU, en_US, etc. Quelques valeurs possibles pour le jeu de caractères: iso-8859-1, utf-8. En combinant les deux, on obtient des définitions telles que les suivantes: export LC_CTYPE=en_US.iso-8859-1 ou export LC_ALL=de_DE.utf-8. Notons aussi les variantes euro: export LC_ALL=fr_LU@euro.iso-8859-15. (à ce jour, pas de locale définie pour lb_LU@euro.iso-8859-15.)

Attention: le terminal peut avoir été lancé ou configuré avec un codage de caractère différent de celui que vous déclarez aux programmes que vous lancez dans ledit terminal. À vous de veillez à ce que cela ne se produise pas, ou à vous arranger avec le résultat (recode(1) peut aider). Si vous avez un terminal graphique, vérifier dans les menus le codage des caractères (anglais: character encoding); Votre bureau graphique, GNOME ou KDE, gère sans doute ces histoires de locale. Si vous utilisez la console Linux, vos scripts de démarrage peuvent configurer la console; à vous de voir selon votre distribution [98]. Et si vous vous loguez à distance, utilisez un codage qui existe sur les deux machines. L'un de ceux-ci devrait fonctionner: en_US.iso-8859-1, en_US.utf-8; au pire, C ou POSIX fonctionne partout, et doit être plus ou moins équivalent à en_US.ASCII et à en_US.ANSI_X3.4-1968.

6.4.3 Multiplexer son terminal

Programme très utile pour multiplexer un terminal et avoir des sessions qu'on peut détacher et rattacher: screen(1) [99].

Emacs est aussi capable de lancer des programmes à l'intérieur d'une fenêtre texte qu'il contrôle, avec M-x shell et M-x terminal. Le même Emacs peut aussi être lancé dans plusieurs fenêtres et/ou terminaux grâce à M-x gnuserv et gnuclient(1).

6.4.4 Programmer son terminal

Pour connaître l'ensemble des séquences d'échappement reconnues par les divers terminaux, voir la base de données termcap(5) et son successeur « moderne » terminfo(5). Pour le terminal que vous utilisez en particulier, rien ne vaut le code source du programme en question. Par exemple, les sources du noyau linux pour la console en mode texte, ou les sources de xterm ou de konsole pour un terminal en mode graphique, etc.

Truc marrant: avec une séquence d'échappement appropriée, on peut changer le titre du terminal dans xterm(1x) ou screen(1). Exercice: lire la doc desdits programmes, et mettre un message simple dans le titre. Exercice plus long: changer son .bashrc ou .zshrc pour mettre le chemin d'accès courant dans le titre de la fenêtre [100].

Mode d'entrée: le terminal possède de nombreux modes de fonctionnement. Avec le mode brut (littéralement cru (anglais: raw) en anglais, utiliser stty raw ou cfmakeraw(2), ou sous zsh(1), la commande interne read -k), les processus connectés au terminal peuvent lire directement tout caractère (ou toute séquence de caractères) saisi(e) au clavier. Cependant, avec le mode par défaut, le mode préparé (littéralement, cuit (anglais: cooked), stty cooked), le gestionnaire de terminal inclus dans le noyau gérera pour les programmes qui ne veulent pas s'en soucier une édition de ligne rudimentaire et d'autres transformations utiles: il n'enverra au programme lecteur le texte saisi qu'après réception de la touche entrée; cela lui permet de gérer l'effacement arrière (BackSpace) et l'annulation de la ligne (C-u), ainsi que le signal de fin de fichier (C-d en début de ligne).

API pour Programmer son terminal. Connexion: termios(3). édition de ligne de commande: readline(3). Écran texte adressable: ncurses(3) (utilise la base de données terminfo(5), ou plus anciennement termcap(5)). Souris: libgpm(3). Graphiques: aalib (essayer bb(1)). Fenêtrage: utilitaires comme dialog(1), plusieurs bibliothèques. Fournir un pseudo-terminal: voir comment faire screen(1).

6.4.5 Déboguer son terminal

Dans les cas simples, remettre une configuration correcte du terminal laissé en rade par un programme improprement interrompu: stty sane.

Remettre complètement à zéro son terminal quand il est vraiment dans un sale état: /usr/bin/reset — normalement, cela fait tout ce qu'il faut.

Autres plantages fréquents, et solutions:

Slogans menteurs: War is Peace. Freedom is Slavery. Ignorance is Strength. [103] BackSpace is Delete [104]. Alt is Meta [105]. Meta is Escape [106]. Your program is 8-bit clean [107]. Your terminal is 8-bit clean [108].

6.5 Connexion à distance

Se connecter à distance: ssh(1). Clefs avec ou sans mot de passe. Sessions pour ne taper sa clef qu'une fois: ssh-agent(1), ssh-add(1). ssh permet aussi de faire des redirections de ports pour accéder à des services de part et d'autre de la connexion (typiquement: accès sécurisé au serveur X et à d'autres services non protégés).

Si c'est pour interagir dans un terminal, screen(1) non seulement vous permettra de multiplexer vos sessions, mais aussi de les reprendre après que la connexion soit interrompue et rétablie (indispensable sur des lignes peu fiables).

Échange de fichiers: scp(1). rsync(1) met à jour en ne transmettant que le nécessaire. unison(1) met à jour dans les deux sens.

scp(1) et son équivalent plus interactif sftp(1) est le moyen sécurisé de transmettre des fichiers personnels (sous Windows: WinSCP2). Le protocole FTP (mon client préféré: lftp(1)) reste un moyen répandu de publier des données, et est aussi utilisé par certains ISP pour des sites ouèbes personnels. Sinon, vous pouvez aussi publier par HTTP, et récupérer ainsi vos fichiers avec n'importe quel navigateur ouèbe.

Au lieu de ssh(1) et consorts, il existait autrefois les programmes rsh(1), rcp(1), rlogin(1), telnet(1). Il ne faut plus les utiliser sur l'Internet, parce qu'ils ne sont pas du tout sécurisés. Cela dit, si vous osez utiliser NFS sur votre réseau local pour rendre vos machines complètement accessibles les unes aux autres, vous pouvez aussi utilisez rsh(1) et consorts. Notez qu'il ne faut pas plus faire confiance au trafic WiFi qu'au trafic externe. Dans les cas où vous voulez faire confiance à l'intérieur de votre réseau, soyez sûr d'avoir un pare-feu efficace aux frontières de votre réseau.

Sécuriser une connexion: enrober un service via SSL, redirection sous SSH, VPN (cas simple: tunnel PPP via ssh(1)), IPSEC voire IPv6, etc. Une fois prises ces précautions élémentaires, la connexion n'est plus le maillon faible de la sécurité de votre installation — mais ce maillon faible existe encore, quelque part, par définition!

6.6 Administration

Un labyrinthe de fichiers de configuration, tous différents.

Heureusement, solutions intégrées pour les cas courants. SuSE: YaST2(8). webmin(8). etc. (Sous Debian ne pas oublier dpkg-reconfigure(8) [109].)

Trouver un fichier de configuration: selon votre distribution, rpm -ql foo | grep /etc ou dpkg -L foo | grep /etc. [110]

Pour bien commencer: si vous avez une tâche qui requiert plus que ne l'offre l'interface d'administration simplifiée, alors commencez par chercher et lire un HOWTO adéquat (exemple: le LDAP-HOWTO pour mettre vos utilisateurs sous LDAP), ou sinon une FAQ.

La bonne façon d'envisager les choses: tous ces fichiers de configuration sont traditionnellement dans un format texte, facilement manipulable par des programmes écrits dans le langage de votre choix, voire par des shells scripts. D'où génération facile, traitement à base de regexp, etc. C'est bien pourquoi perl et ses rivaux, qui manipulent si facilement du texte, sont malgré tous leurs défauts les outils préférés des administrateurs UNIX! Ainsi, on peut gérer semi-automatiquement une machine ou un parc de machine, régénérant automatiquement la configuration de chaque machine à partir de templates manuellement configurées, etc.

Il n'y a pas de « base de registre » comme sous Windows, ce qui n'est pas forcément un mal, car cela permet aux programmes d'avoir comme configuration des données plus structurées et plus riches que celles qui sont exprimables en termes de « registres » contenant chacun un entier, une chaîne, etc. Cela permet aussi la sauvegarde séparée des fichiers, leur traitement automatique par les outils de manipulation de texte « habituels » ou par des outils adaptés à chacun des programmes configurés, etc. Et le seul avantage réel de la base de registre, à savoir la sauvegarde globale, est toujours possible, grâce au fait que tout est sous la hiérarchie /etc.

<rant> Si vous développez des logiciels, SVP, employez du texte simple pour la configuration. Si cela ne suffit pas, si vous avez besoin de structuration, ou si vous cherchez une certaine uniformisation, alors adoptez des S-expressions à la LISP (cf. isapnp). Mais par pitié, n'utilisez pas du XML. XML n'est qu'un métalangage, un langage dans lequel définir des sous-langages, au même titre que « fichier texte ». Et le peu que l'on gagne avec XML, on le perd mille fois en complexité. Beaucoup ont essayé. Ils s'y sont cassé les dents. S'ils ont persisté, le résultat est gros, lent, laid, horrible à utiliser. </rant>

Ne pas oublier que les fichiers personnels des utilisateurs (y compris root) peuvent interférer avec la configuration globale de /etc. Si vous avez un doute sur ce que fait un processus, utilisez en fin de compte strace(1).

6.7 Impression

À la base, c'est simple, et ça peut être un plaisir: administrer avec les outils intégrés à votre distribution (ouf!); combiner des programmes avec des tuyaux pour produire du PostScript, et l'envoyer en fin de compte dans lpr(1) (avec lpr -Pnom_de_l_imprimante si on veut choisir une autre imprimante que celle par défaut, que l'on peut personnaliser avec la variable d'environnement PRINTER). Cool!

Mais dès qu'on veut faire plus, c'est galère: configurer avec CUPS vs LPRng vs BSD lpd; interfacer avec Windows ou MacOS avec samba(7), netatalk; configurer un imprimante non PostScript, voir une imprimante multifonction(!); installer de nouvelles polices de caractères...

Ah, les polices! L'horreur! Mais ça s'améliore au fil du temps. Par contre, les problèmes de copyrights sur les polices...

Pas d'API unifiée pour l'impression: chaque programme fait son manège. Le seul standard, c'est de produire PostScript. Essentiels: les utilitaires à tout faire comme a2ps(1), mpage(1), psutils, etc. GNOME, KDE, Java, proposent chacun leur propre API pour l'impression. Beaucoup utilisent (La)TeX comme backend pour produire du PostScript à partir de texte. Sinon, voir comment font vos programmes favoris: TeXmacs, a2ps(1), cl-typesetting, etc.

6.8 Compiler un programme

Savoir lire les READMEs et autres INSTALL.

Dans les cas un peu plus compliqués, il faudra comprendre un peu make(1) et le fonctionnement d'un Makefile. La connaissance de rudiments du shell pourra être utile.

Bien gérer son /usr/local avec des liens symboliques: utiliser stow(8) et similaires (et pour nettoyer, symlinks(1)).

6.9 Le noyau et ses modules

Chercher d'abord une mise à jour sur sa distribution. Ou de la documentation en relation avec votre distribution. Consulter les HOWTO.

Malheureusement, certaines fonctionnalités nécessitent une recompilation à la main. Toutefois, même là, il y aura des paquets de votre distribution pour vous faciliter la tâche.

Après avoir compilé votre noyau, attention à bien mettre à jour LILO ou GRUB. LILO plus « bas niveau » et statique que GRUB: le relancer quand les fichiers cibles ont changé. GRUB: à relancer seulement si GRUB a changé. Avec liens symboliques, pas besoin de changer le /etc/lilo.conf ou le /boot/grub/menu.lst. Notez que sous SuSE, par exemple, il faut aussi régénérer le ramdisk d'initialisation des modules avec mkinitrd(8).

Précaution essentielle: Toujours garder une ancienne version dont on est sûr qu'elle marche!!! Cela comprend le noyau, ses modules, fichiers de configuration, et s'il le faut, entêtes, sources, patches, etc. Votre distribution peut vous aider à empaqueter tout ça.

7 Quelques Exercices

Voici quelques exercices à faire chez vous ou en cours. Notez que le jour de l'examen, il vous sera demandé de faire des exercices similaires.

7.1 Exercice permanent

Ces notes de cours sont incomplètes: aidez à les compléter.

Il manque des URL vers certains concepts, programmes, documents et autres sites mentionnés. Trouvez ces sites grâce à Google.

Certains paragraphes nécessitent éclaircissements. Notez quels paragraphes, et pour des points supplémentaires, suggérez des éclaircissements après avoir lu la documentation ou consulté Google.

Certains paragraphes seraient bien illustrés avec des exemples. Fournissez de tels exemples.

Sauvez toutes vos suggestions dans un fichier texte, et envoyez-les moi à la fin du cours à l'adresse: fare@tunes.org.

7.2 Exercice d'administration de base

Créer un utilisateur à votre nom sur votre machine avec l'interface graphique ou useradd(8). Dupliquer depuis root les fichiers de l'utilisateur cepl1 du serveur avec cp -a. Note 1: si vous n'êtes pas root, vous ne pourrez pas lire certains fichiers protégés. Note 2: le répertoire où la configuration par défaut se trouve est /etc/skel. Utiliser un chown(1) pour changer le possesseur de la nouvelle arborescence et passwd(1) pour changer le mot de passe. (Solution [111])

S'il n'existe pas encore, créer le groupe cepl. Mettre votre utilisateur et les autres du genre cepl dans le groupe cepl. S'il n'y a pas d'utilisateur cepl1, en créer un dans le groupe cepl. (Indice [112])(Solution [113])

Installez de nouveaux paquets logiciels depuis les sources déjà configurées sur votre machine [114]. Ainsi par exemple, les paquets suivants vous seront utiles pour la suite du cours: a2ps xv ImageMagick [115].

7.3 Exercice de configuration graphique

Aller dans le control center de KDE, kcontrol.

Activer ou désactiver l'économiseur d'écran (anglais: screensaver).

Créer des bureaux virtuels.

Faire mumuse avec les fontes.

Activer le double clic au lieu du simple clic.

S'amuser à découvrir les multiples tableaux de bords.

À noter si vous déréglez la chose et voulez restaurer son état initial que la disposition (anglais: layout) du clavier au Luxembourg est celle du clavier Suisse français.

7.4 Copie d'écran

Un outil graphique fort utile malgré son âge est xv(1) [116]. Avec xv(1), vous pouvez capturez des fenêtres avec le bouton grab du menu disponible en cliquant sur la fenêtre avec le bouton droit. Configurez les cases délai (anglais: Delay) et cacher les fenêtres de xv (anglais: Hide xv windows) et utilisez Grab ou AutoGrab selon que vous préférez cliquer sur la fenêtre à capturer ou le laisser capturer la fenêtre sur laquelle se trouvera la souris passé le delai. Pointez sur le fond d'écran (s'il en reste) pour obtenir une capture de l'ensemble de l'écran. Une fois une fenêtre capturée, vous pouvez transformer l'image et enfin utiliser le bouton de sauvegarde (anglais: Save) du menu pour sauver l'image au format de votre choix.

Un paquet logiciel contenant de nombreux outils graphiques est ImageMagick. Il comporte notamment un outil convert(1) pour convertir les fichiers d'un format à un autre, un outil display(1) pour afficher des images, un outil import(1) pour les importer [117], et d'autres outils encore (voir ImageMagick(1)). Vous pouvez ainsi faire une copie de tout l'écran avec import -window root toto.png que vous pouvez par exemple précéder d'un appel à sleep(1) pour avoir le temps de mettre l'écran dans l'état souhaité: sleep 3; import ...

7.5 Burn All GIFs!

Le but de ces exercices est d'apprendre à maîtriser la programmation de shell scripts simples à base de combinaison de petits utilitaires utilisant des expressions régulières.

Ces manipulations seront illustrées sur un cas réel, celui du Burn All GIFs: UNISYS, détenteur d'un brevet sur la technique de compression LZW, telle qu'utilisée notamment par le format de fichier graphique GIF, a décidé il y a quelques années de menacer de poursuites judiciaires ceux qui créeraient les fichiers GIFs et les publieraient sur leurs pages ouèbes sans avoir acquis une licence à $5000. En protestation, des activistes du logiciel libre ont organisé le Burn All GIFs day (littéralement, « jour pour brûler tous les GIFs ») durant lequel les participants furent conviés à remplacer tous leurs fichiers GIFs par des fichiers équivalents au format PNG, qui produit des fichiers de meilleure qualité et de taille plus petite. [118] [119]

Nous allons vous proposer d'écrire un shell script de dix lignes qui vous permettra d'économiser $5000 si jamais UNISYS décide de vous envoyer une lettre comminatoire. Le script comportera deux parties: d'abord, trouver tous les fichiers GIF et les convertir en PNG; ensuite, trouver tous les fichiers HTML, et remplacer chaque référence à un fichier GIF en une référence au fichier PNG correspondant.

En préliminaire, vous récupérerez un petit site ouèbe sur lequel travailler. Je vous propose de reprendre le Cours UNIX de l'INT EVRY. J'ai mis ce cours sur le serveur ltc-141-00 dans le répertoire /home/cepl1/tutoriel, et j'ai exporté le répertoire /home par NFS. Récupérez le répertoire chez vous. (Indice [120])(Solution [121]) Si vous êtes chez vous, vous pouvez vous aussi télécharger ce cours, grâce à l'outil wget(1). (Solution [122])

Votre première étape est donc de localiser tous les fichiers GIFs dans l'arborescence du site ouèbe. Pour simplifier, on supposera que la convention est respectée selon laquelle leur nom se termine en .gif, et que ce nom ne comporte pas d'espace ou de caractère spécial pour le shell. (Indice [123])(Solution [124])

Votre deuxième étape est d'itérer sur cette liste de fichiers, c'est­à-dire de savoir effectuer une même opération successivement sur chacun de ces fichiers. L'opération pour le fichier FOO sera simplement d'afficher Nous traiterons le fichier FOO. (Indice [125])(Solution [126])

La troisième étape sera d'arriver à obtenir automatiquement un nom de fichier se terminant par .png pour chaque fichier GIF dont le nom se terminait par .gif.

D'abord, ce qui marchera même sous le shell antique d'un UNIX propriétaire, vous utiliserez l'outil sed(1), de la façon suivante: sed -e 's/expression régulière à remplacer/expression de remplacement/g' [127] pour transformer le nom de fichier GIF (mis sur la sortie standard de sed(1)) en nom de fichier PNG. Ensuite, pour récupérer ce nom dans une commande du shell, vous devrez utiliser les backquotes `...`. (Solution [128])

En fait, avec un shell non antique, on peut aussi écrire ${file%.gif} pour enlever la désinence .gif du nom de fichier contenu dans la variable file. Voir le manuel de votre shell pour les détails. On peut ainsi écrire directement newfile=${file%.gif}.png. [129]

Notez que pour les shells antiques, il existe aussi des utilitaires basename(1) et dirname(1) permettant d'extraire chemin et nom de base d'un fichier. Exercice pour ceux qui veulent devenir des pros du shell: réimplémenter les fonctionnalités de ces utilitaires avec l'expansion de variable des shells modernes. (Solution [130])

Pour tester votre troisième étape, essayez sans boucle de définir la variable file avec file=toto.gif et d'appliquer votre recette au contenu de la variable file. Puis, vérifiez que vous savez bien combiner cette étape avec la précédente en appliquant votre recette à tous les fichiers GIF trouvés.

La quatrième étape sera de convertir le fichier GIF en fichier PNG, en utilisant l'utilitaire convert(1) du paquet ImageMagick.

La cinquième étape, optionnelle, sera de détruire le fichier GIF originel après l'avoir converti en PNG. (L'opération conservant a priori toute l'information, il n'y a pas de danger particulier, en dehors de la nécessité valable en tout temps d'une sauvegarde régulière de vos données.) Pour plus de sécurité, utiliser l'exécution conditionnelle du shell pour que l'opération ne soit effectuée que si l'opération précédente a été réalisée avec succès [131].

Dans une deuxième partie, commencez par vérifier que vous savez itérer sur les fichiers HTML, de même que vous saviez itérer sur les GIF.

L'opération à effectuer sur chaque fichier sera de remplacer dans le texte toutes les occurrences de .gif en .png [132]. (Indice [133])(Solution [134])

Une fois que vous avez une commande qui marche, il suffit de faire une redirection < $file > $file.new puis, si la commande n'a pas échoué, remplacez l'ancien fichier par le nouveau avec mv $file.new $file [135].

Maintenant que vous savez tout faire, mettez-moi ça dans un script, c'est-à-dire un fichier exécutable commençant par #!/bin/interpréteur_de_commande. Pour éviter d'aller trifouiller et faire de la recherche-remplacement dans tout le système bien au-delà des fichiers visés [136], il est important de changer de répertoire au début du script, et de quitter le script avec une erreur si le changement de répertoire ne s'est pas effectué correctement.

Notez que pour qu'un programme puisse être exécuté sans donner son nom complet mais seulement son nom de fichier de base, il doit être dans votre PATH. Les personnes qui écrivent des scripts les rajoutent traditionnellement dans leur $HOME/bin qu'ils rajoutent dans leur PATH avec une ligne du genre PATH="$HOME/bin:$PATH" dans leur .profile ou .bashrc ou équivalent pour leur shell. Exercice: sauver le script de cette exercice dans votre $HOME/bin et le mettre dans votre PATH. (Solution [137])

Enfin, vous pouvez tester le script obtenu dans diverses situations [138].

Bravo! vous venez d'écrire une dizaine de lignes de code qui peuvent vous économiser $5000. Maintenant, l'univers Linux est à vous, car vous pouvez l'affronter sans crainte. Apprenez par l'exemple, en lisant les scripts et programmes des autres, et en partant vaillamment à la recherche de documentation, tutoriels, manuels, HOWTOs, FAQs, etc. La communauté des utilisateurs est là pour vous aider.

7.6 Pour les plus avancés...

Outre le fait de compulser divers sites, je vous invite à inspecter le système.

Par exemple, repérez les exécutables dans votre $PATH, et avec file(1), identifiez parmi eux les scripts; lisez ces scripts en commençant par le plus court, et comprenez de quoi il s'agit. (Solution [139])

Apprendre à compiler et installer un programme qui n'est pas déjà sur le système: Télécharger décomprimer les sources dans ~/src (ou ailleurs). Lire le fichier INSTALL, README, LISEZMOI, 00INSTALL, etc. Suivre les instructions. En l'absence d'instructions, essayer ./configure ; make ; make install.

Utilisation de make(1).

Inspection de ce que font divers processus simples avec strace(1), lsof(8), etc.


Notes

[1]: Si vous voulez avoir une vue à la fois simple et puissante de ce en quoi consiste effectivement une machine de Von Neuman, sans vous encombrer des détails inutiles, mais en en suçant la substantifique moëlle et en atteignant facilement des sommets, je vous invite à apprendre le langage FORTH, par exemple avec le petit livre Thinking FORTH de Leo Brodie. Si vous êtes fasciné par les détails des machines réelles, que le progrès rapide des technologies rend aussi éphémères qu'abscons, il sera toujours temps d'apprendre le langage d'assemblage de quelque machine. Pour commencer, je vous déconseille fortement l'assembleur des ordinateurs PC à base d'Intel IA-32 (x86); préférez-y l'élégant assembleur des ARM, processeurs répandus dans les matériels embarqués et PDA, dont certains comme les Zaurus tournent sous Linux; à défaut, choisissez le PowerPC des Macintosh.

[2]: Les informaticiens, qui comptent en base 2, préfèrent compter avec les puissances dixièmes, vingtièmes et trentièmes de 2, qui valent respectivement 1.024, 1.048.576 et 1.073.741.824.

Autrefois, et parfois encore maintenant par approximation, on employait et on emploie improprement les termes kilooctets, mégaoctets, gigaoctets, etc., pour faire référence à ces quantités. En fait, les préfixes kilo-, Méga-, Giga-, etc., sont normalisés comme représentant un facteur multiplicatif par une des puissances de 1.000. Ainsi, un kilooctets (anglais: kilobyte), noté ko (kB) ou souvent improprement Ko (KB), vaut 1.000 octets; un mégaoctets (anglais: megabyte) noté Mo (MB) vaut 1.000.000 octets; un gigaoctets (anglais: gigabyte) noté Go (GB) vaut 1.000.000.000 octets, etc.

Pendant longtemps, les informaticiens utilisaient les mêmes préfixes kilo, méga, giga, etc. en parlant de puissances de 1.024 ou de 1.000, la chose étant claire selon le contexte. C'est notamment toujours le cas quand ils parlent de tailles de mémoire vive. Ce fut aussi longtemps le cas en parlant de taille de disques durs; mais pour pouvoir gonfler leurs chiffres marketing de 7.3%, les fabricants de disques durs se sont mis à utiliser 1 Go = 1.000.000.000 octets plutôt que 1 Go = 1.073.741.824 octets comme les informaticiens s'y seraient attendus (d'autant que traditionnellement, il était bien ancré que dans l'usage courant 1 ko = 1.024 octets et 1 Mo = 1.048.576 octets, même pour les disques durs).

Pour éviter plus de confusion, et parce qu'il est effectivement impropre de détourner kilo-, Méga-, Giga-, etc., de leur sens normalisé, de nouveaux préfixes ont été inventés et normalisés pour les variations binaires des préfixes précédents: Kibi-, Mébi-, Gibi- et ainsi de suite (remplaçant la deuxième syllabe par le bi de binaire), qui désignent les multiplicateurs par puissance de 2^10 plutôt que de 10^3, et qui s'écrivent dans les calculs en introduisant un -i- après le du préfixe de la puissance de 10^3 correspondante. Ainsi, les préfixes Ki-, Mi-, Gi-, Ti-, Pi-, etc., sont ainsi utilisés pour 2^10, 2^20, 2^30, 2^40, 2^50, etc., par analogie et par contraste avec k-, M-, G-, T-, P-, E-, Z-, Y-, etc., qui sont dorénavant bien réservés pour 10^3, 10^6, 10^9, 10^12, 10^15, etc. (Notez que les informaticiens ont capitalisé le K de Ki pour régulariser la majuscule qui était impropre dans le très courant KB). Le noyau Linux utilise notamment ces préfixes, de même que de nombreux logiciels libres, et si possible tous les logiciels futurs, libres ou pas. Toutefois, les logiciels et documents plus anciens parlent encore à l'ancienne manière.

Pour en savoir plus, voir: units(7), et les pages du NIST, de l'IEC, ou de Wikipedia.

[3]: Dans les années 1960, le nom originel du fait de pouvoir faire tourner plusieurs programmes à la fois était multiprogrammation (anglais: multiprogramming). Le mot multitâche s'est imposé avec la tradition Unix.

[4]: Certains systèmes ou surcouches logicielles gèrent plus ou moins automatiquement la persistence (anglais: persistence) des données; on parle alors de persistence orthogonale (anglais: orthogonal persistence), par opposition à une persistence explicite. Mais comme une telle automatisation n'est pas généralisée, même dans des systèmes « modernes » comme Linux, Windows XP ou Mac OS X, il faut savoir utiliser la persistence explicite, et comprendre son fonctionnement.

[5]: Le petit nombre entre parenthèses fait référence à la section du manuel où on trouvera la documentation relative à la commande donnée. Pour le manuel et la liste de ses sections, voir la commande man(1): man 1 man (dans ce cas man man suffit, cependant que pour accéder à la documentation du format de fichiers de man(7), il faut faire man 7 man). La commande whatis(1) donnera la liste des pages de manuel de même nom dans des sections différentes.

[6]: Certains ordinateurs, des multiprocesseurs (anglais: multiprocessors) contiennent plusieurs processeurs en même temps qui partagent la même mémoire. Dans de tels cas, le noyau se charge de partager ces ressources supplémentaires entre les processus actifs. Les programmes sont toujours écrits essentiellement comme pour un seul processeur; le noyau maintient la même illusion d'une machine virtuelle isolée pour chaque processus, quel que soit le nombre de processeurs disponibles.

[7]: Les appels systèmes sont spécifiés pour leur utilisation depuis le langage C. Mais en fait, ont peut les utiliser quasi à l'identique voire en mieux depuis à peu près n'importe quel langage. Préférer Perl, Python, Ruby, Ocaml, Common Lisp, etc.

[8]: Le manuel de l'utilisateur est disponible avec la commande man(1), ou un navigateur graphique comme khelpcenter. Il est aussi disponible en-ligne sur le ouèbe, et il y a même des versions papier chez divers éditeurs.

[9]: Ainsi, si vous vous demandez « mais qu'est-ce que fait ce programme? », ou « mais comment ça marche? », utilisez strace -o strace.log programme arguments... puis (ou dans une autre fenêtre) inspectez le fichier strace.log. C'est très instructif sur le fonctionnement du noyau Linux.

[10]: Sous Linux, un utilisateur (anglais: user) est identifié par son numéro d'utilisateur (anglais: UID), un nombre entier positif plus petit que 4.294.967.295 (ou 65.535 sur les anciens systèmes). Chaque utilisateur n'a que les droits que l'administrateur système lui a accordé; il ne peut typiquement contrôler complètement que les fichiers qu'il a créé, n'ayant qu'un contrôle limité sur le reste du système. La correspondance entre numéro d'utilisateur et nom de login et autres propriétés n'est pas gérée par le noyau mais par la librairie standard via ses appels d'API getpwent(3) et similaires. Par défaut, cette correspondance se fait via le fichier /etc/passwd, mais on peut la configurer autrement (LDAP, etc.) via le fichier de configuration /etc/nsswitch.conf. La description des fichiers de configuration sont dans la section 5 du manuel: man 5 passwd ou man 5 nsswitch.conf.

[11]: D'où le nom de la commande standard su(1) pour devenir super-utilisateur. Dans le genre mais plus élaboré, voir aussi sudo(8) et toute une floppée d'outils similaires.

[12]: Le pid est accessible avec l'appel système getpid(2), ou dans un shell avec la variable $$.

[13]: La mémoire est divisée en pages (anglais: pages) (de 4 KiB sur les PC x86, souvent autant ou plus sur d'autres machines), qui sont chacune mappée (anglais: mapped) sur une partie d'un objet géré par le noyau. Une partie de cette mémoire sera mappée en lecture seule vers le fichier exécutable (anglais: executable file) du programme lancé et vers les bibliothèques partagées (anglais: shared libraries) qu'il utilise. Une autre sera mappée sur la mémoire privée du processus. Le programme peut aussi mapper des segments de mémoire partagée entre plusieurs processus, ou des fichiers de travail. On peut examiner les zones de mémoires mappées par un processus avec cat /proc/$PID/maps — essayez, c'est instructif. Notez que /proc/self/ correspond au processus qui fait l'appel système (qui n'est pas forcément le shell d'où une commande est lancée).

On peut examiner l'état du calcul d'un processus grâce à l'appel système ptrace(2). Cet appel est notamment utilisé par des programmes comme gdb(1) qui sert à déboguer une applications en cours d'exécution, ou strace(1) qui sert à observer les interactions d'un processus avec le reste du système.

[14]: Cet état peut être typiquement actif (anglais: running), endormi (anglais: sleeping), terminé (et avec un code résultat; il sera détruit qu'après que le processus père lise ce code), ou en attente de réponse du système, voire zombi (anglais: zombie) si le processus est presque mort mais pas tout à fait (typiquement, il lui est arrivé malheur au beau milieu d'un appel système).

On peut changer l'état du processus en lui envoyant un signal (anglais: signal) avec la commande kill(1). Pour une liste des signaux, voir signal(7). Certains signaux peuvent aussi être interceptés par les processus, et l'on peut parfois faire des choses avancées avec (jouer avec la mémoire virtuelle protégée), mais alors c'est une horreur à programmer, et il y a parfois des bugs bizarres du noyau ou des bibliothèques standard, notamment avec des signaux qui sont perdus s'ils sont envoyés pendant qu'un signal précédent était en cours de traitement, ce qui arrive souvent si le système est trop chargé, etc. Bref, la façon dont fonctionne les signaux n'est pas toujours fiable quand il s'agit de faire de la programmation avancée, surtout si vous n'avez pas le bon processeur avec le bon noyau, les bonnes bibliothèques, le bon programme. Pour les utilisations simples, ils fonctionnent bien, pour le reste, il faut être prêt à affronter les bugs du système.

[15]: Le noyau ne voit que des numéros d'uid et de gid, qui sont donnés par l'administrateur au moment où l'utilisateur se logue (ou au moment où un démon est lancé), d'après les tables du système à ce moment là (fichiers passwd(5) et group(5), etc.). Si l'administrateur modifie le numéro d'un utilisateur ou les noms ou les numéros des groupes associés, les processus existant ne seront pas modifiés, et il faudra que l'utilisateur se délogue et se relogue (ou que les démons utilisant cette identité soient relancés), pour que les processus correspondant voient les changements. Voilà le genre de phénomènes qui ne s'explique bien que si on comprend le modèle de base de fonctionnement du système.

[16]: Pour pouvoir permettre à d'autres utilisateurs d'exécuter certains programmes en son nom, un utilisateur (typiquement, root), peut activer un attribut spécial de certains fichiers exécutables, le bit s (voir la commande chmod(1)). On dit que le programme est setuid (du nom de l'appel système qui a l'effet de changer d'utilisateur, quand la chose est autorisée). Le programme peut alors jongler entre deux identités, et un processus possède alors des uid et gid effectifs et de sauvegarde (euid, egid, suid, sgid — voir les appels systèmes seteuid(2), setresuid(2), etc.). mais en général, l'exercice est dangereux voire casse-gueule, un trou de sécurité étant si vite arrivé. Dans la pratique, on vérifie les droits d'accès, on vérifie les paramètres d'appels, on nettoie l'environnement, et on exécute un programme après avoir complètement changé d'identité et sécurisé l'environnement. Exercice: utiliser la commande find(1) pour trouver tous les fichiers setuid du système... Application typique pour les programmes setuid: écrire un programme qui permet à tous les utilisateurs de la salle d'enlever les travaux d'impression (anglais: printing jobs) d'une imprimante partagée. Pour tout service plus compliqué que ça, on préférera un démon qui écoute sur le réseau, éventuellement contrôlé par inetd(8) (ou xinetd(8)): c'est plus propre, plus contrôlable, plus sûr; moins de risque d'erreur qui créerait un trou de sécurité.

[17]: Un autre attribut intéressant d'un processus est qu'il peut avoir un répertoire racine différent du répertoire habituel, grâce à l'appel système chroot(8), réservé à l'administrateur. L'administrateur peut ainsi donner des droits restreints à des processus (notamment des serveurs), ou permettre à des programmes installés sur un autre disque ou provenant d'une autre distribution de tourner « comme à la maison », par exemple, installer une Debian sous sa SuSE ou réciproquement, ou corriger un système en mauvais état après avoir booté sur disquette. Voir aussi le paquet dchroot sous Debian, et les options --bind et --rbind de mount(8).

Dans ce dernier cas, certains programmes (par exemple ps(1)) requerront que l'on monte aussi /proc en double sous /altroot (ou quelque soit la nouvelle racine): mount proc2 /altroot/proc -t proc Pour que le système n'ait pas de problème avec la table de montages dans /proc/mounts, il peut être judicieux de faire aussi un cd /altroot ; ln -s . altroot

[18]: Pour une gestion plus fine des droits d'accès sur le système, un processus peut posséder des capabilités qui lui permettent d'accéder à certaines parties du système (on peut aussi restreindre son accès davantage que la normale, en lui accordant moins de capabilités que l'habitude). C'est une fonctionnalité (anglais: feature) disponible mais encore peu exploitée du système Linux.

[19]: Pour ouvrir diverses sortes d'objets systèmes, voir dans la section 2 du manuel (man 2 toto) les appels système suivants et les appels affiliés: open(2) proc(5) pipe(2) mknod(2) socketpair(2) socket(2) accept(2) bind(2).

[20]: dans le shell, se change avec cd et s'interroge avec pwd.

[21]: Les enfants existent encore après terminaison, avec mémoire libérée, etc., jusqu'à ce que le parent lise le code de retour. Typiquement, 0 quand tout s'est bien passé, un code d'erreur entre 1 et 255 sinon.

Les appels systèmes correspondants sont fork(2), execve(2), wait(2). Pour communiquer avec les enfants, voir aussi pipe(2), select(2). Voir aussi les fonctions de librairie system(3), popen(3), etc.

La terminologie n'est pas claire pour savoir si les processus sont mâles ou femelles, pères ou mères, fils ou filles; tous les cas se rencontrent. Voir aussi les pages de manuel sex(6) et condom(1).

[22]: Par exemple, une priorité, que l'on peut changer avec nice(1) ou renice(8). Ou encore des moyens de communication inter-processus selon les protocoles définis par la norme Unix Système V (SYSV IPC) — man 2 ipc. Pour vraiment tout savoir sur les processus, le seul moyen est de lire les sources du noyau Linux, dont diverses versions sont largement documentées dans divers livres en-ligne ou papier. (Demander à Google Linux.) (Certains disent que les sources des systèmes BSD sont souvent plus compréhensibles et mieux documentés.)

[23]: À vrai dire, il est possible de lire (mais pas d'écrire) l'environnement d'un autre processus via /proc/$PID/environ, et s'échanger des droits d'accès et des descripteurs de fichiers via les "ancillary data" de sendmsg(2) et recvmsg(2) (fonctionnalité obscure documentée dans unix(7)). Mais cela suppose que les processus partagent déjà une socket de domaine unix, et pour le contact initial entre deux processus, on est donc ramené au problème précédent: ou bien ils l'ont hérité d'un parent qui aurait utilisé socketpair(2) ou autre, ou bien le serveur a une socket nommée, qu'il a rendue visible sur le système de fichier avec une commande du genre bind(3, {sa_family=AF_UNIX, path="/tmp/.X11-unix/X0"}, 19) (exemple extrait du strace(1) de l'exécution d'un serveur X).

[24]: Appels systèmes fork(2) puis execve(2).

[25]: Dans le langage C autour duquel Unix est défini, le comportement d'une commande à son lancement est spécifié par une fonction main, qui prend en argument le nombre des paramètres et un tableau contenant ces paramètres. En raison d'une convention de programmation en C, le caractère de numéro 0 n'est pas représentable dans les chaînes de caractère standards du C (il sert de terminateur), et ne peut donc être présent dans les paramètres d'une commande.

Notez qu'en tout premier argument, l'argument 0, nommé $0 dans les shell-scripts, il y a le nom du programme appelé tel que fourni par le programme appelant. Il s'agit par convention du chemin menant effectivement au programme appelé, mais l'appelant peut spécifier ce qu'il désire. La plupart des programmes ne consultent pas ce nom sous lequel ils sont invoqués, et ne s'occupent que des véritables paramètres. Toutefois, certains programmes changent leur comportement selon le nom sous lequel ils sont invoqués: ainsi, l'outil à tout faire pour systèmes embarqués busybox(1) change de personnalité selon son nom d'invocation; un shell détectera s'il est shell de login avec la convention que le programme login(8) précèdera son nom d'un caractère '-'; certains programmes notamment des shells ont des « modes de compatibilité » qui s'activent quand ils sont appelés avec le nom d'un ancien programme qu'ils savent remplacer.

[26]: Toutes les variables d'environnement sont internées comme variables disponibles dans le shell. Mais toutes les variables internes du shell ne sont pas forcément visibles comme variables d'environnement pour les commandes exécutées: pour cela, il faut les définir FOO=toto puis les exporter (anglais: to export) avec export FOO dans le shell POSIX de base, ou les définir et les exporter d'un seul coup export FOO=toto avec bash(1), zsh(1) ou ksh(1), ou avec setenv pour csh(1) et tcsh(1). En C, voir les appels d'API getenv(3) et putenv(3) et l'appel système execve(2). Pour votre langage préféré, consulter la documentation adéquate.

[27]: On peut distinguer un fichier dont le commençant par - d'une option en précédent le nom du fichier d'un chemin d'accès, par exemple ./-foo pour le fichier -foo du répertoire actuel. Ainsi, si vous créez par erreur un fichier -foo, vous pouvez l'effacer avec rm ./-foo.

[28]: Ainsi, si vous créez par erreur un fichier -foo, vous pouvez aussi l'effacer avec rm -- -foo.

[29]: Consultez le jargon ou le jargon français pour la signification de mots bizarres comme « foo ».

[30]: Toutefois, quand on accède à un système de fichier du monde Windows, le noyau va faire en sorte que les noms de fichiers correspondant à majuscule ou minuscule près vont magiquement correspondre au même fichier ou répertoire.

[31]: Attention qu'avec les liens symboliques, le père d'un sous-répertoire n'est pas forcément le répertoire actuel, si ledit sous-répertoire est en fait un lien symbolique.

[32]: Ou avec l'appel système stat(2).

[33]: Cela évite le risque d'avoir à gérer le cas où on couperait de la racine une arborescence qui serait liée en boucle, par exemple: mkdir foo ; cd foo ; ln . bar ; cd .. ; rm -rf foo

[34]: Pour éviter un plantage en cas de liens circulaires, le noyau ne suit les liens que jusqu'à une certaine profondeur limitée.

[35]: Ainsi, on pourra par exemple monter la partition / en lecture seule et faire un lien symbolique de /tmp vers /var/tmp/var a été monté en lecture-écriture. Ou encore, on pourra monter de nombreux fichiers par NFS sur un nœud au nom physique /serveur et faire des liens de /home vers /serveur, etc. Pour le cas où /serveur serait indisponible, on peut aussi créer des liens sous le nœud où /serveur est monté pour pointer vers une location par défaut où chercher quelques fichiers essentiels de remplacement.

[36]: Exemple d'utilisation des liens durs pour créer plusieurs versions:

tar zxvf $ARCHIVE/v1.0.tar.gz
chmod a-w v1.0/**/*(.)
cp -al v1.0 v1.1
cd v1.1 ; zcat $ARCHIVE/v1.0-v1.1.diff.gz | patch -p1 -E
chmod a-w v1.1/**/*(.)
cp -al v1.1 v1.2
cd v1.2 ; zcat $ARCHIVE/v1.0-v1.1.diff.gz | patch -p1 -E
cp -al v1.1 v1.1-localfork
cd v1.2 ; bzcat $ARCHIVE/v1.1-localfork.diff.bz2 | patch -p1 -E
cp -al v1.2 courant
On peut alors modifier la version 1.2 pour lui apporter les modifications correspondant à ce qu'on avait fait subir à la version 1.1 dans la branche locale v1.1-localfork. Les outils diff(1) et diff3(1) peuvent se révéler très utiles, de même que patch(1).

Notons que cet exemple fonctionne bien parce que patch(1) ne modifie pas l'original (qui peut donc être partagé), mais le remplace par une copie modifiée; un tel partage par lien dur ne donnera par les résultats escomptés si certains programmes modifient directement des fichiers partagés par d'autres versions.

[37]: Affichez les droits du répertoire /tmp, avec ls -ld /tmp) et voyez le bit sticky noté par t à la fin des droits Le répertoire /tmp et son éventuel petit copain, /var/tmp (qui est parfois un lien vers /tmp ou vice-versa), voire plus rarement /usr/tmp (qui s'il existe est souvent un lien symbolique vers /var/tmp), sont des endroits dans lequel par convention les programmes stoquent des fichiers temporaires. Ainsi par exemple, quand on compile, des fichiers produits par le préprocesseur ou donnés à l'assembleur ou à l'éditeur de lien y sont stoqués. Tout le monde a donc les droits d'écriture sur ce répertoire. Sans le sticky bit, documenté notamment dans la page de chmod(1), un utilisateur mal intentionné pourrait alors détruire le fichier temporaire d'un autre et le remplacer par un fichier au contenu maléfique (ver, virus, etc.). Mais avec ce bit (noté t comme temporaire, justement?), seul le propriétaire du fichier ou celui du répertoire (ou root) peut effacer ou renommer ledit fichier. Cela bouche ainsi un trou de sécurité béant qui existait originellement. Si par mégarde vous effacez /tmp et le recréez, n'oubliez donc pas un chown root.root /tmp ; chmod 1777 /tmp

[38]: voir la commande mount(8) et les fichiers fstab(5), /etc/mtab, /proc/mounts.

[39]: voir les commandes ls -l, ln -s, les appels système readlink(2) et lstat(2). Pour détecter et nettoyer les liens cassés, il y a aussi l'utilitaire symlink(1)

[40]: apropos(1) est identique à man -k.

[41]: À noter que les réseaux sous Windows utilisent TCP/IP, et que Linux peut être un serveur grâce à samba(7), ou un client grâce à smbclient(1) ou smbmount(8).

[42]: Un processus sait en général à quel serveur s'adresser par la variable d'environnement DISPLAY. Avec votre shell: echo $DISPLAY. Pour dire à votre commandes d'utiliser le premier (et par défaut le seul) serveur de la machine courante, utiliser export DISPLAY=:0. Pour la gestion des droits d'accès, voir les commandes xhost(1x), xauth(1x). Souvent, le serveur n'est configuré pour n'accepter que des connexions locales; pour les connexions distantes, redirection par ssh(1), ou changer la configuration dans /etc/X11/. Si vous utilisez la mire automatique xdm, kdm ou gdm(8), allez voir dans le répertoire correspondant.

[43]: startx(1x) est un shell script qui appelle la commande xinit(1x) (regardez un peu voir son source avec less `which startx` ou sous zsh(1), less =startx). En configurant proprement les bonnes commandes, on peut aussi lancer plusieurs serveurs X, chacun sur sa console virtuelle.

Si vous jouez à lancer des serveurs X à la main, ou avant que le système soit complètement initialisé, attention que si plusieurs processus son ouverts sur la même console virtuelle et utilisent des modes clavier différents, votre clavier peut devenir non-fonctionnel. Un serveur X gravement planter (mauvais driver de carte graphique) peut aussi laisser votre clavier dans le mauvais mode. Si votre clavier est dans le mauvais mode, depuis un ssh(1) distant ou en survivant en copiant-collant avec la souris, utiliser kbd_mode(1) pour remettre le clavier dans le bon mode. Notez qu'avec le copy-paste de la souris, vous pouvez parfois entrer dans un shell assez de commandes pour reconfigurer le clavier (ou changer de console virtuelle avec chvt(1)). Autre solution: les touches magiques du noyau Linux, voir /usr/src/linux*/Documentation/sysrq.txt.

[44]: Ceux d'entre vous qui ont le cœur bien accroché pouvez aussi consulter mes fichiers de configuration personnels qui sont disponibles dans toute leur horreur par CVS. Diverses écoles d'ingénieur fournissent aussi des configurations utilisateur par défaut dont vous pouvez vous inspirer. Dernière note: pensez à consulter la configuration par défaut de votre shell dans /etc avant toute une personnalisation sérieuse; j'ai souvent eu à désactiver la @$^#%&! de configuration fournie par défaut sur ma machine.

[45]: Ces shells sont typiquement des shells POSIX assez minimaux, mais pouvant être statiquement liés, et intégrant les fonctionnalités de nombreux programmes comme ls(1), mv(1), etc., ce qui leur permet de récupérer un système dont le mécanisme de bibliothèques partagées est cassé par une mauvaise manipulation, ou de fournir le plus possible des outils habituels dans le moins possible de place pour déploiement dans des systèmes embarqués limités en mémoire. Pour la récupération de système en tout confort, il est aussi possible de compiler statiquement zsh(1).

[46]: Attention: si le shell n'est pas parmi ceux listés dans shells(5) alors divers services vont considérer l'utilisateur comme ayant des droits restreints. Solution: si vous êtes administrateur, ajoutez votre shell dedans. Sinon, avoir /bin/sh comme shell officiel, et terminer votre .profile par un exec /path/to/your/favorite/shell. Les précautions d'usage s'imposent quand vous faites cela.

[47]: Dans le cas rare mais fort gênant où deux administrateurs tentent simultanément d'éditer ledit fichier, il peut y avoir des étincelles et des plantages graves. Pour prévenir une telle catastrophe, l'utilitaire vipw(8) est censé lancer votre éditeur favori (tel que spécifié dans $EDITOR ou par défaut vi(1)) sur le fichier avec un verrou qui évitera de tels désagréments. Si vous êtes le seul administrateur de la machine, cette précaution peut paraître superflue, mais elle peut néanmoins être un bon réflexe à acquérir si vous comptez jamais devenir administrateur d'un système multi-administrateur.

[48]: Sous zsh(1) voir aussi la variable RPROMPT.

[49]: La touche BackSpace est souvent vue comme C-h ou C-? ou le caractère ASCII 127; La touche Delete est souvent égale à C-? ou une séquence d'échappement du genre ^[[3~. Voir la discussion dans la section sur les terminaux.

[50]: Si on est au milieu d'une ligne, on pourra utiliser C-k pour se mettre en fin de ligne en effaçant ce qui suit, et C-y pour récupérer ce qui suit après avoir fini la complétion.

[51]: Pour ne pas avoir à payer le coût d'une recherche dans tout le $PATH à chaque commande, le shell se souvient du contenu des répertoires indiqués après la première recherche. Pour le forcer à regarder à nouveau, on peut utiliser la commande interne hash -r.

[52]: Parfois, le shell peut vous dire que l'exécutable n'est pas trouvé, alors que le programme existe visiblement; ce peut alors être dû au fait que le programme en question est un script (dont la première ligne commence par le signe #! suivi de la commande à lancer pour invoquer un interpréteur de script) mais que l'interpréteur spécifié lui n'est pas trouvé.

[53]: La commande rm(1) efface sans rémission. Une fois supprimé le dernier lien dur vers un fichier, ledit fichier n'existe plus et il n'y a pas de undelete possible. Pour éviter des erreurs trop faciles, le shell permet parfois d'insérer automatiquement l'option -i (avec alias rm='rm -i') ou de demander confirmation avant un rm *, mais ce sont des pis-aller.

Il existe d'autres programmes plus sympathiques pour déplacer un fichier vers une zone intermédiaire (comme la corbeille (anglais: trash can) de MacOS ou Windows), mais aucun n'est un standard présent dans tout le monde UNIX, et ces divers programmes n'interopèrent pas. Notez toutefois que l'interface graphique de KDE ou celle de GNOME offrent les deux options distinctes, mettre à la corbeille et supprimer.

La seule solution « standard » et « fiable » pour éviter de perdre des données par mégarde est d'avoir des backups réguliers. Et cette solution, si elle est bien réalisée (copie dans un lieu sûr loin de l'ordinateur lui-même), vous couvre contre bien plus qu'une erreur humaine somme toute infréquente: elle vous couvre contre un plantage du disque dur, un incendie, un vol, etc. Pour les sauvegardes, voir la commande tar(1), ou pour un système de fichier entier, la commande dump(8); dans un autre genre, les commandes rsync(1) et unison(1) peuvent aussi s'avérer précieuses.

Il peut aussi être de bon ton de mettre ses fichiers importants sous un système de gestion de versions, comme cvs(1), ou ses remplaçants plus modernes (voir section ci-dessus "Habitudes élémentaires de précaution"). Ce qui n'empêche pas de faire une sauvegarde des fichiers de cvs(1) ou autre.

[54]: Concernant le souci d'effacer vraiment un fichier de façon fiable sans rémission aucune possible (pour raison de confidentialité, avant de vous séparer d'un disque ayant contenu des données sensibles), notez que quelqu'un disposant du disque et de plusieurs milliers d'euros et pourra toujours demander à des ingénieurs équipés d'une platine haute précision dans chambre blanche de récupérer les données sur votre disque même après que le système ait écrasé vos fichiers et écrit par dessus deux ou trois fois.

Si vous tenez à la confidentialité, utilisez une commande appropriée comme shred(1), sur votre fichier (si le système de fichier le permet) ou sur toute la partition (sinon). Peut-être les systèmes de fichiers journalisés les plus modernes ont-ils un mécanisme spécial pour spécifier que certains fichiers doivent se comporter de façon à permettre un tel effacement sûr; en tout cas, se méfier de ce que si les données ont été écrites avant qu'un tel mécanisme ait été utilisé, alors elles sont potentiellement lisibles à moins d'effacer de façon sûre toute la partition.

Si vous en êtes à de telles considérations, vous devriez songer à crypter l'ensemble de vos données, ce qui sous Linux peut se faire en utilisant dm-crypt ou loop-aes.

[55]: Voici pour déboguer un script qui affiche ses arguments:

#!/bin/zsh -f
# Ceci est un commentaire
# L'option -f est utile pour un script, voir la page de manuel.
print -r "ARGC=$#"      # Afficher le nombre d'arguments
print -r "argv[0]=$0"   # Afficher le nom sous lequel le programme est appelé
i=1                       # initialiser la boucle
while [ "$i" -le "$#" ] ; do # tant qu'on a pas vu tous les arguments
  print -r "argv[$i]=$*[$i]"   # afficher l'argument actuel
  i=$[i+1]                       # passer à l'argument suivant
done                             # retour en boucle
En voici un autre, utilisant bash
#!/bin/bash
# Ceci est un commentaire
echo "ARGC=$#"      # Afficher le nombre d'arguments
echo "argv[0]=$0"   # Afficher le nom sous lequel le programme est appelé
x=1                   # initialiser le compteur d'arguments
for i ; do            # pour chacun des arguments donnés
  echo "argv[$x]=$i"	         # afficher l'argument actuel
  i=$((i+1))                     # incrémenter le compteur d'argument
done                             # retour en boucle
En voilà un dernier, n'utilisant que des fonctionnalités standard POSIX:
#!/bin/sh
# Ceci est un commentaire
echo "ARGC=$#"      # Afficher le nombre d'arguments
echo "argv[0]=$0"   # Afficher le nom sous lequel le programme est appelé
x=1                   # initialiser le compteur d'arguments
while [ "$#" -ne 0 ] ; do        # tant qu'il y a encore des arguments
  echo "argv[$x]=$1"	         # afficher le premier argument
  x=`expr $x + 1`                # incrémenter le compteur d'argument
  shift				 # laisser tomber le premier argument
done                             # retour en boucle
Pour afficher les arguments d'une commande en cours d'exécution, essayer: cat /proc/$PID/cmdline | tr '\0' '\n'

[56]: Solution: echo image{{0-9},{1-9}{0-9},1{0-9}{0-9},2{0-4}{0-9},25{0-5}}.gif














[57]: La convention est que login invoquera le shell avec un tiret '-' devant le chemin de son binaire comme argument numéro 0. Sous zsh(1), on peut invoquer un programme avec un argument 0 différent du chemin d'accès grâce à la variable ARGV0man zshparam.

[58]: Voir la commande tty(1). Voir sous bash(1) la variable $tty ou sous zsh(1) la variable $TTY.

[59]: Voir par exemple mon choix d'options pour zsh(1) dans mon zshrc.opts.

[60]: L'historique des commandes peut être fort utile, mais peut aussi être une source de vulnérabilité, car des ennemis peuvent espionner vos habitudes, les maladresses que vous commettez, vos manquements aux règles de sécurité, les mots de passe que vous auriez tapé au mauvais endroit, etc. En général, je conseille de désactiver la fonctionnalité qui sauve l'historique dans un fichier, sauf ponctuellement pour enregistrer explicitement une session.

[61]: Utiliser cut(1) pour isoler le champ idoine du fichier passwd(5) puis utiliser le tri de sort(1) avec l'option d'unicité pour éliminer les doublons.














[62]: < /etc/passwd cut -d: -f7 | sort -u














[63]: Utilisez la commande cut(1).














[64]: find . -type f | cut -c 3-
Sous zsh(1), avec le globbing étendu, il suffit de **/*(.).














[65]: Un script robuste doit être capable de traiter des noms de fichiers contenant espacements et retour à la ligne; on utilisera alors find ... -print0, xargs -0 ... et sous zsh(1), print -N ....

[66]: Dans le genre pager alternatif, voir aussi most(1), et bien sûr w3m pour le HTML.

[67]: mail(1) est un programme UNIX très ancien (début des années 1980), et chaque distribution Linux utilise un des nombreux programmes qui réimplémente le mail original (tel que vu sur des UNIX propriétaires) en l'enrichissant de nombreuses options. Toutefois, l'interface pour envoyer des attachements par exemple n'est pas standardisée, aussi la version répandue mailx(1) installée sous Debian ne les connaît pas, tandis que l'implémentation nail(1) installée sous SuSE, les connaît. Si vous voulez envoyer des attachements depuis un script portable, appelez explicitement nail(1), mutt(1) ou autre plutôt que mail(1) qui sur une machine ou une autre ne réagira pas selon vos attentes.

[68]: gzip(1) (fichiers .gz ou pour des vieilles versions, .z, même compression que le programme zip(1)), mais aussi bzip2(1) (fichiers .bz2, successeur de bzip(1), sans brevets logiciels), lzop(1) (fichiers .lzo, légèrement moins bon mais plus rapide que gzip(1)), bzip(1) (fichiers .bz, prédécesseur de bzip2 arrêté à cause de brevets logiciels), tzip(1) (fichiers .tz, n'a jamais eu le succès de bzip2), compress(1) (fichiers .Z, ancien programme de mauvaise qualité avec problèmes de brevets logiciels, mais longtemps standard officiel sous UNIX), pack(1) (fichiers .z, programme antique peu performant) etc.

[69]: Comprimés en .tar.bz2 ou .tar.gz ou .tar.Z (souvent appelés plus simplement .tb2, .tbz, .tgz, .taz, .trz), etc. Autres types d'archives: pax(1) (fichiers .pax), cpio(1) (fichiers .cpio), ar(1) (fichiers .a), shar(1) (fichiers .shar — exécutables par un shell, attention aux virus shell). Et archives déjà comprimées: unzip(1) (fichiers .zip) zoo(1) (fichiers .zoo), lha(1) (fichiers .lzh), unarj(1) (fichiers .arj), rar(1) (fichiers .rar), etc. Connaître aussi uuencode(1) (ou des variantes comme xxencode(1), rendus obsolètes maintenant par le standard MIME pour l'email (cf. le programme mimencode(1)).

[70]: Notez que par tradition, et comme exception aux conventions habituelles, les options de tar ne nécessitent pas de tiret quand elles sont en première position. Vous pouvez le rajouter si vous êtes courageux.

Notez aussi que la version de tar(1) du projet GNU, utilisée par défaut sous Linux, reconnaît aussi les fichiers comprimés avec bzip2(1) via l'option j plutôt que z.

[71]: Pour les amateurs de mathématiques, il y a une jolie théorie des langages réguliers, des automates à états finis, etc. Voir Wikipédia.

[72]: grep attention cepl-linux.html














[73]: grep -l cepl /etc/* — pour éviter les messages d'erreur de grep(1) tentant de lire un répertoire comme un fichier, utiliser plutôt grep -l cepl /etc/* 2> /dev/null (ou, sous zsh(1), grep -l cepl /etc/*(.))














[74]: On pourra combiner grep(1) et wc(1).














[75]: On peut compter le nombre de lignes où apparaît le mot « foo » dans le fichier cepl-linux.html avec la commande grep foo < cepl-linux.html | wc -l. Notez que si on voulait compter les occurrences du mot foo en comptant les répétitions sur la même ligne, il faudrait utiliser un programme un peu plus compliqué, comme par exemple celui-ci perl -e 'while (<>) { while ( s/.*?foo// ) { $x++; } } ; print "$x\n" ;' . Voir un tutoriel de perl pour en savoir plus.














[76]: Je suis peut-être le seul à encore utiliser netscape 3.

[77]: La commande file(1) permet de déterminer le type d'un fichier: file /bin/ls, ou file `which ls` ou sous zsh(1) avec setopt MAGIC_EQUAL_SUBST, file =ls.

[78]: La version de ld.so(8), comme celle des autres bibliothèques chargées, dépend de ce qui a été utilisé lors de la compilation du programme. Utiliser ldd(1) pour voir quelles bibliothèques sont demandées par le programme. Notez que le nom .so signifie composant exécutable partagé (anglais: shared object).

[79]: Voir aussi avec ldd(1). Les bibliothèques dynamiques sont censées rester compatibles tant qu'elles ont le même numéro de version majeure, et changer de numéro de version majeure (ou carrément de nom) quand un changement incompatible est fait à l'API. Ainsi, on peut mettre à jour les bibliothèques et faire profiter tous les programmes des corrections de bugs et de trous de sécurité, tout en faisant coexister des programmes qui utilisent des versions incompatibles des bibliothèques dynamiques (avec des noms ou numéro majeur de version différent). Par exemple, sous Linux i386, libc.so.6 est la version 6 de l'API binaire de la bibliothèque standard pour tous les programmes C (qui correspond pour le source de cette bibliothèque à la GNU libc version 2, ou glibc2).

[80]: Le répertoire /lib contient les bibliothèques essentielles pour les programmes indispensables du système. Le répertoire /usr/lib contient les bibliothèques pour le reste des programmes. Le fichier ld.so.conf(5) peut préciser des chemins additionnels.

[81]: Pour accélérer la recherche, il y a un cache dans /etc/ld.so.cache, qu'on doit régénérer avec ldconfig(8) quand on modifie l'installation des bibliothèques partagées. Normalement, votre distribution lance cette commande au bon moment, mais c'est bon à savoir si vous trafiquez les choses manuellement.

[82]: Exemple: la bibliothèque SOCKS, qui permet de centraliser les accès à travers un pare-feu ou tunnel, utilise ce mécanisme.

[83]: Vous pouvez consultez les mappings mémoire d'un processus avec cat /proc/$PID/maps (exemple: pour le processus cat(1) lui-même, cat /proc/self/maps).

[84]: Notez la différence de niveau d'abstraction par rapport à strace(1): dans un cas, on regarde ce qui se passe au niveau de l'API, dans l'autre, au niveau du noyau. Notez aussi que si on en fait l'effort, il est possible de tricher avec l'API, en la court-circuitant pour certains appels systèmes, ou en triturant manuellement les mécanismes de liaison dynamique; mais il n'est pas possible de tricher avec le noyau.

[85]: Si vous faites une manipulation qui déplace ou efface /lib, assurez-vous qu'un programme déjà chargé saura en remettre immédiatement après un nouveau qui marche, ou gardez un shell statiquement lié (anglais: statically linked) (i.e. qui marche sans avoir besoin de bibliothèque partagée) et/ou des un shell déjà ouvert et des versions statiquement liées des programmes cp(1), mv(1) et ln(1). Ce sera notamment le cas quand vous remplacerez « à chaud » une distribution par une autre que vous aurez installée en chroot(8).

[86]: On peut changer le format de sortie. Ainsi, pour mes logs j'utilise parfois: date +"%Y-%m-%d %H:%M:%S".

[87]: La date à la seconde près est accessible avec date +%s. C'est utile pour faire des comparaisons simples d'antériorité dans des shells scripts, notamment en conjonction avec l'option -r de date(1).

[88]: La fin du monde aura lieu très précisément à la fin de la seconde indiquée par date -u -d "1970-01-01 00:00:00 UTC + $((2 ** 31 - 1)) seconds". (Pourquoi se casser la nénette à faire de la dichotomie soi-même quand l'ordinateur est là pour faire tout le travail?) D'ici là, les stations de travail seront toutes 64 bits, ce qui nous laissera du temps pour voir venir lors du prochain milliard de siècles; mais il y aura peut-être des problèmes avec les applications legacy et avec des antiques systèmes embarqués, sans parler des programmes que nous ferons tourner avec émotion nostalgique dans des émulateurs. Mais que feront donc les conservateurs des musées informatiques dans 100 voire 1000 ans?

[89]: Voir par exemple un simple programme que j'ai écrit en ce sens: faketime.

[90]: Certaines machines antiques et même certaines moins antiques de chez IBM, utilisent d'autres codes que le code ASCII. Les machines de chez IBM utilisent notamment l'EBCDIC, codage optimisé pour le système à cartes perforées qui a fait la fortune du fondateur d'IBM au xixe siècle. Nous jetterons un voile pudique sur de telles pratiques.

Notons l'usage du programme recode(1) pour transcoder les caractères entre les multiples codages existant.

[91]: Sous UNIX et les autres systèmes moderne, ASCII est omniprésent; par contre, entre tous ces systèmes, les variantes d'ASCII sont nombreuses pour gérer les caractères accentués et autres spécialités locales. Dans les pays occidentaux comme le Luxembourg, le codage sur 8-bit selon la norme ISO-8859-1 (Latin 1) est le plus répandu, quoique le ISO-8859-15 (Latin 9) est aussi utilisé depuis l'introduction de l'EURO. Mais le codage sur taille variable UTF-8 de la norme ISO-10646-1 (Unicode) s'implante lentement mais sûrement à l'échelle mondiale, car il permet de traiter tous les caractères de tous les pays du monde.

Le choix de la langue et du jeu de caractères affichable se fait principalement (mais pas uniquement) via les variables d'environnement définissant la locale(1).

[92]: Ceux qui connaissent cette spécificité française reconnaîtront peut-être là le principe familiarisé par le minitel.

[93]: Même quand on peut, par exemple avec le mode Tektronix de xterm(1x), c'est complexe de mise en œuvre pour un résultat décevant et pas portable, donc personne n'utilise. Il y a quand même des hacks sympathiques comme w3m-img ou aaview, chacun dans leur genre particulier.

[94]: Toutefois, la chose vaut en sens inverse: la plupart des discours ne peuvent pas être traduits en graphiques. Une interface entièrement graphique serait complètement inutilisable. Le mode graphique est meilleur que le mode texte précisément par qu'on peut aussi faire du texte, et en mieux (avec fontes de diverses polices, taille, couleurs, etc.) en mode dit « graphique ».

[95]: Les terminaux X comme xterm, konsole, gnome-terminal, Eterm, etc. permettent de copier-coller à la souris. Sous la console Linux, le démon gpm(8) aussi. Sinon, screen(1) ou emacs(1) permettent de copier-coller au clavier.

La configuration est pénible et malaisé, se faisant en partie dans les paramètres de chaque application, en partie dans les variables d'environnement (et donc dans les fichiers de démarrage du shell), en partie dans divers fichiers systèmes, qui peuvent varier d'une distribution à l'autre.

[96]: Normalement, TERM est géré automatiquement par Linux. Toutefois, il peut y avoir des problèmes quand vous vous loguez sur Linux depuis une machine dont le terminal est mal configuré, ou quand vous vous loguez depuis Linux (ou autre) sur une machine mal configurée dont vous n'êtes pas administrateur. Le terminal de référence: export TERM=vt100. Le terminal le plus stupide possible: export TERM=dumb. Entre les deux, consultez le fichier /etc/termcap, ou sa version sur Internet. Si votre terminal n'est pas reconnu par le système distant où vous vous loguez sans être administrateur, configurer la variable $TERMINFO ou $TERMCAP selon ce qu'utilise ledit système, voire recompiler votre propre sous-système GNU avec terminfo(1), etc.

[97]: Si un programme qui sait d'habitude gérer la taille de la fenêtre du terminal n'a pas pris conscience qu'elle a changé, on peut lui envoyer le signal SIGWINCH avec kill -WINCH $PID. Voir aussi les options rows, columns et -a de stty.

[98]: Ainsi, sous Debian, le fichier /etc/environment est consulté par d'aucuns scripts de /etc/init.d qui l'utilisent pour initialiser la console. grep(1) est votre ami pour trouver lesquels.

[99]: Truc marrant à essayer: on peut rattacher plusieurs fois la même session, dans plusieurs fenêtres, par plusieurs personnes.

[100]: Solution: voir mon zshrc.tty.

[101]: Les shells modernes sauvent l'état du terminal à chaque fois, et s'ils utilisent pour eux-mêmes le mode cru, ils remettront le mode que vous aurez défini avec stty et autres programmes quand vous exécutez des commandes externes.

[102]: Ces caractères sont configurables ou désactivables via stty(1) ou l'équivalent par termios(3). Il est déconseillé que vous les modifiiez, mais certains programmes interactifs le font, et il faut savoir reconnaître la chose. Emacs utilise notamment C-g au lieu de C-c pour se faire envoyer le signal SIGINT.

[103]: Pour les trois slogans précédents, lire 1984 de George Orwell.

[104]: Il y a deux conventions principales pour les codes des touches BackSpace et Delete. Parfois, BackSpace est C-h, et Delete est le code ASCII 127. Parfois, BackSpace est C-?, et Delete est le code ASCII 127. Parfois, BackSpace est C-h, et Delete est le caractère C-?. Parfois, BackSpace est C-?, et Delete est la séquence ESC [ 3 ~. Bref, tout le monde n'est pas d'accord. Normalement, l'intégrateur qui a préparé votre distribution a choisi une convention et s'y est tenu. Mais des programmes que vous installerez par la suite, ou situés sur une machine distance, etc., pourraient n'être pas d'accord.

[105]: Pour des raisons historiques, dans les configurations des claviers PC. la touche perçue par le système comme la touche Meta est celle qui porte le symbole Alt. La touche perçue par le système comme la touche Alt est alors la touche (d'apparition plus récente) portant le symbole de Windows.

[106]: Le fait que la touche Meta soit enfoncée est en général représenté par le terminal en envoyant le caractère ESC (ASCII 27, hexadécimal 0x1B, octal 033) avant la séquence habituelle de la touche. Quoique parfois, dans de vieilles configurations datant d'avant l'usage répandu des caractères accentués, ça envoie le caractère avec le bit 8 changé.

[107]: Les vieux terminaux étaient 7-bit et n'acceptaient que les caractères sans accents du jeu ASCII de base. Du coup, les vieux programmes utilisaient parfois le huitième bit pour quelques astuces diverses. Les programmes modernes ne font pas ça. Par contre, ils peuvent ne pas traiter correctement le caractère NUL (de code ASCII 0), ou se comporter bizarrement avec d'autres caractères (par exemple, shells scripts se plantant quand il y a des espaces ou autres caractères spéciaux dans un nom de fichier, etc.).

[108]: Tous les terminaux ne laissent pas tout passer. Un rlogin(1) ou ssh(1) par défaut accepte des commandes spéciales avec un ~ au début de la ligne. Pour telnet(1) c'est plutôt C-]. Pour un modem, c'est typiquement A T au début de la ligne, éventuellement suivi d'une attente de trois secondes. Avec les bonnes options, on peut désactiver tout cela. Sans parler des séquences d'échappement, etc., qui font que certains caractères ne sont accessibles qu'avec des séquences magiques.

[109]: Si problème de la configuration de Debian unstable, pour le paquet foo, modifier /var/lib/foo.*. Pour éviter tout tel désagrément, utiliser stable ou testing.

[110]: Pour les utilisateurs avancés: si tout le reste échoue, utiliser strings foo | less -p /etc sur le binaire ou observer le programme avec strace(1). Au pire, lire les sources.

[111]:

useradd toto -d /home/toto
cp -a /mnt/cepl1/. /home/toto/.
chown -R toto /home/toto
passwd toto














[112]: Utiliser l'outil graphique YaST2, ou utiliser interactivement addgroup(8) puis adduser(8), voire appeler groupadd(8) puis useradd(8) avec la bonne ligne de commande. sans oublier l'option -m. Si vous voulez, vous pouvez aussi éditer à la main les fichiers passwd(5) shadow(5) group(5) gshadow(5) et dupliquer à la main une entrée.














[113]:

groupadd cepl
useradd cepl1 -m -g cepl














[114]: Sur les machines du LTC, il s'agit de nfs://172.16.141.0/suse/cd1 jusqu'à nfs://172.16.141.0/suse/cd4.

[115]: Je vous rappelle que pour savoir si un paquet est installé, vous pouvez utiliser rpm -qa | less -p foo, et que pour avoir des informations sur le paquet foo, il y a rpm -qi foo et rpm -ql foo. J'attire aussi votre attention sur l'option -i de less(1) et de grep(1). Si la page de manuel ne vous simplifiait pas la tâche, vous pourriez aussi repérer tous les programmes du paquet ImageMagick avec rpm -ql ImageMagick | grep /bin de même que vous pouvez repérer les fichiers de configuration avec rpm -ql ImageMagick | grep /etc.

[116]: Simple, petit, robuste, rapide, avec toutes les fonctionnalités essentielles, xv(1) est un logiciel encore très pratique de nos jours, même si le fait qu'il ne soit pas vraiment un logiciel libre fait que son développement est arrêté depuis 1994, et que cela se ressent quant à son interface.

La documentation de xv(1) est dans un fichier PostScript (à imprimer ou visionner avec gv(1) ou l'un des logiciels cités dans la section précédente appropriée), parfois distribuée dans un paquet à part — dans la distribution Debian, le paquet xv-doc.

Votre distribution vient sans doute avec de nombreux logiciels plus récents, comme gimp(1), Electric Eyes, etc., et bien sûr imagemagick(1) dont il est question plus loin.

[117]: Notez qu'on pourrait obtenir la fonctionnalité d'import en combinant xwd(1) et convert(1): import toto.png est équivalent à xwd | convert xwd:- toto.png.

Cependant, sur ma station de travail, la version de xwd(1) que j'utilise (issue de XFree86 4.3.0) ne fonctionne pas sur l'écran entier quand je suis en mode TrueColor 16 bits. Par contre, import(1) marche correctement; il y a donc un bug de xwd(1). Bug que personne ne prend le temps de corriger parce que personne n'utilise plus trop xwd(1). Mais si quelqu'un en ressentait le besoin, il pourrait facilement corriger ce bug (s'il existe encore à l'heure où vous lisez ces notes): c'est un avantage des logiciels libres que si un bug vous dérange, vous pouvez le corriger vous-même ou le faire corriger par l'expert de votre choix au prix du marché, sans être en situation de dépendance face à un fournisseur en situation de monopole de droit.

[118]: Un problème du format PNG était qu'il n'est pas supporté par tous les anciens navigateurs: il est reconnu par Netscape 4 et IE 4.5 (?), mais pas les versions antérieures. De plus, on me dit que la transparence, qui est bien définie en PNG, ne fonctionne pas avec Netscape 4, ni avec IE 5 (voire 6?)... à tester. En tout cas, Mozilla et Konqueror n'ont pas de problème avec.

[119]: À cause de ce même brevet, les systèmes libres ne livrent pas dans leur version de base l'outil standard compress(1) des UNIX propriétaires, remplacé par l'outil gzip(1), de meilleure qualité. Notez que gunzip(1) sait décomprimer les fichiers produits par compress(1). Dans les années 1990, PKware a dû de même cesser de vendre sont logiciel à succès PKARC et le remplacer par PKZIP. gzip(1) et png(5) utilisent tous deux le même algorithme de compression que PKZIP et son successeur WinZip, qui a accédé au statut de standard de l'Internet avec la RFC 1951 de mai 1996.

Le brevet est expiré depuis 2003 aux États-Unis, où UNISYS dispose encore de 3 ans pour poursuivre les personnes l'ayant utilisé sans sa permission. En Europe, le brevet n'est pas encore expiré, mais la situation légale est telle qu'il n'y aura sans doute pas poursuites. Ailleurs dans le monde, il y a sans doute des pays où le brevet est valide. Donc il n'est pas impossible que vous ayiez un jour à faire une telle opération. À moins qu'une opération similaire ne soit rendue nécessaire à cause d'un autre brevet, comme celui sur les MP3 que vous aurez alors peut-être à transformer massivement en Ogg Vorbis, etc.

De toute façon, c'est un acte symbolique fort pour signifier votre refus de l'extorsion que constitue les brevets logiciels. (Sur ce dernier sujet, voir mon article Patents are an Economic Absurdity.)

[120]: Utiliser l'outil YaST2 pour faire le montage, puis Konqueror pour faire la copie. À la ligne de commande, utilisez mount(8) puis cp(1).














[121]: mount ltc-141-00:/home /mnt ; cp -a /mnt/cepl1/tutoriel ~/














[122]: wget -r http://etna.int-evry.fr/COURS/UNIX/
Notez toutefois que wget(1) est assez rudimentaire, et que pour aspirer des sites nécessitant plus de subtilité, l'outil w3mir(1) est plus configurable.














[123]: Utiliser l'outil find(1), ou sous zsh(1), le globbing.














[124]: bash: find . -name '*.gif' -print
En fait, le -print est optionnel sous les versions modernes de find(1).
zsh: print -l **/*.gif














[125]: Pour itérer, utiliser for file in ... ; do ... ; done.
Plus délicat, pour récupérer la sortie d'un programme comme argument d'une commande shell, utiliser $(...)














[126]:


for file in $(find . -name '*.gif') ; do
  echo "Nous traiterons le fichier $file" ;
done
Sous zsh, ceci marche aussi:

for file ( **/*.gif ) { echo "Nous traiterons le fichier $file" }














[127]: Le g final indique qu'il ne faut pas s'arrêter au premier remplacement possible sur une ligne. Sans cette option, la recherche et remplacement ne ferait qu'un seul remplacement sur une ligne comportant plusieurs fois la chaîne .gif.

[128]:

newfile=` echo $file | sed -e 's/\.gif$/.png/' `
Notez bien le $ pour être sûr de remplacer une désinence. En fait, il ne serait pas indispensable, si vous êtiez sûr que .gif n'apparaît pas ailleurs que dans le nom d'un fichier.














[129]: En fait, sur un shell non-antique, la commande newfile=${file//.gif/.png} effectuera le remplacement désiré avec une expression régulière.

[130]: On a l'effet de b="$(basename $i $foo)" avec temp="${i%$foo}" ; b="${temp##*/}" et de d=$(dirname $i) avec case $i in */*) d=${i%/*} ;; *) d=. ;; esac.














[131]: Une erreur possible dans une telle opération est que le disque soit plein ce qui aura pour effet que vous ne puissiez pas créer les fichiers PNG, mais que vous puissiez effacer les fichiers GIF. Le résultat d'une suppression inconditionnelle du fichier GIF serait donc une perte pure et simple de vos données! (Et le recours coûteux en temps à une sauvegarde, si tant est que vous en avez une.)

[132]: (Encore une fois, cela marche tant que l'on connaît de quoi il s'agit, qu'il n'y a pas de liens à conserver vers des GIFs externes, car les images sur d'autres sites n'auront pas été converties, ou de texte (comme cette phrase même!) contenant des allusions spécifiques à des fichiers foo.gif par opposition à un simple pointeur vers une image locale.

[133]: Pour tester votre opération de remplacement par expression régulière sur un fichier foo, vous pouvez utiliser sed -e '...' foo | less, voire mieux sed -e '...' foo | diff -u - foo | less.














[134]: Une solution simple est sed -e 's/\.gif/.png/'.














[135]: Notez qu'en interactif, si mv est un alias pour mv -i, vous devrez éviter l'alias avec \mv ou appeler directement l'exécutable /bin/mv (ou =mv avec zsh) pour ne pas avoir à confirmer à chaque fois.

[136]: Pour éviter de faire de grosses bévues, il vaut aussi mieux ne pas expérimenter avec des commandes pendant que vous êtes logué comme root. Comme dit le proverbe: il y a deux sortes d'administrateurs système, ceux qui ont déjà fait une grosse connerie sur leur machine, et ceux pour qui ça ne va pas tarder.

[137]: Rien de bien méchant, mais n'oubliez pas de faire un

echo 'PATH="$HOME/bin:$PATH"' >> ~/.bashrc
et de relancer un shell ou de faire source ~/.bashrc pour que la modification soit prise en compte.














[138]: Voici une version du script:

#!/bin/sh

cd /home/test/tutoriel || exit 42

for gif in $(find . -name '*.gif') ;
do
   png=`echo "$gif" | sed -e 's/\.gif$/.png/'`
   convert $gif $png &&
   /bin/rm $gif
done

for html in $(find . -name '*.html') ;
do
   sed -e 's/.gif/.png/g' < $html > $html.new &&
   /bin/mv $html.new $html
done

Vous pouvez le tester par exemple aussi dans un répertoire avec une image linux.gif trouvée sur Google Images et le ficher index.html comme suit:

Voici une image: <img src="linux.gif" alt="manchot linux">

Avec zsh, on peut simplifier le script ainsi:

#!/bin/zsh -f
cd "$1" || { echo "Usage: $0 répertoire" >& 2 ; exit 42 }
for file in **/*.gif ; do
   convert $file ${file%.gif}.png && \rm $file
done
for file in **/*.html ; do
   sed -e 's/\.gif/.png/g' < $file > $file.new && \mv $file.new $file
done

Zut! J'aurais dû déposer un brevet sur ce script, et vendre ce brevet à UNISYS, pendant qu'il en était encore temps. Amers regrets.

[139]: Avec bash(1),

PROGRAMS="$(find ${PATH//:/} -xtype f -maxdepth 1 -perm +111)" ;
SCRIPTS="$(file $PROGRAMS | grep script | cut -d: -f1)" ;
SORTED="$(ls --sort=size --reverse $SCRIPTS)" ;
echo "$SORTED"| less
Passez au fichier suivant (next) avec :n et au précédent (previous) avec :p. Notez que vous auriez aussi pu utiliser SORTED=$(ls -lL $SCRIPTS | sort -k 5 | cut -c61-), et que sous zsh, vous utiliserez plutôt:
PROGRAMS=( $(find $path -xtype f -maxdepth 1 -perm +111) );
SCRIPTS=( $(file $PROGRAMS | grep script | cut -d: -f1) ) ;
SORTED=( $(ls --sort=size --reverse $SCRIPTS)
print -l $SORTED | less )














Faré RideauCours CEPLSite by Faré RideauDonate: bitcoins 1fareF6wCNYYiLPGmyQjrd3AQdHBb1CJ6 or paypal