Administration Unix - CM séance 02
3. Manipulations simples de contenus
3.1. Entrées/sorties
Un programme en cours d'exécution s'appelle un processus (le programme peut être une commande, un shell, un éditeur de texte, ...).
Chaque processus possède sa propre liste de fichiers ouverts :
- le numéro d'un fichier dans la liste s'appelle le descripteur du fichier ;
 - cette liste s'appelle la table des descripteurs du processus.
 
Un processus dispose de trois fichiers pour les entrées/sorties :
- l'entrée standard (descripteur 0)
 - la sortie standard (descripteur 1)
 - la sortie d'erreurs (descripteur 2)
 
Par défaut :
- l'entrée standard est le terminal (qui lit le clavier)
 - les sorties standard et d'erreurs sont dirigées vers le terminal (qui affiche ce qu'il reçoit).
 
3.2. Redirection vers un fichier
Le shell permet de rediriger une entrée ou une sortie avec les symboles 
< ou > lorsqu'on entre une commande.
Pour rediriger l'entrée standard :
$ commande -options < fichier
ou encore
$ commande -options 0< fichier
Ceci exécutera la commande en redirigeant son entrée standard (0) depuis le fichier :
- lorsque la commande lira son entrée standard, elle lira en réalité dans le fichier ;
 - la commande ne saura pas qu'elle lit un fichier !
 
Pour rediriger la sortie standard (1) :
$ commande -options > fichier1
ou encore
$ commande -options 1> fichier1
Le fichier1 sera créé ou écrasé.
Exemple
$ echo -e "porte\nsous\nalarme" > idesecours    # crée le fichier
$ cat idesecours                                # affiche le fichier
porte
sous
alarme
$ sort < idesecours                             # fichier en entrée
alarme
porte
sous
Il peut y avoir une erreur lors de l'écrasement :
$ echo > toto       # crée fichier
$ echo > toto       # l'écrasement provoque une erreur
bash: toto : impossible d'écraser le fichier existant
$ set +C            # on autorise l'écrasement
$ echo > toto       # écrasement ok
$ set -C            # on revient au mode par défaut
$ echo > toto       # écrasement interdit
bash: toto : impossible d'écraser le fichier existant
$ echo >| toto      # syntaxe pour forcer l'écrasement (sans utiliser set +C)
On peut aussi rediriger en ajout :
$ commande -options >> fichier1
ou encore
$ commande -options 1>> fichier1
Le fichier1 sera créé ou ouvert en ajout à la fin (mode append).
Pour rediriger la sortie d'erreur (2) :
$ commande -options 2> fichier2
Exemple
Exemple typique avec une commande qui fait des erreurs :
$ echo "ga tor" > ali ; mkdir alu
$ grep tor al*
ali:ga tor                      # ligne trouvée par grep
grep: alu: est un dossier       # message d'erreur de grep
$ grep tor al* 2> erreurs.txt
ali:ga tor                      # on ne voit que les lignes trouvées
$ cat erreurs.txt
grep: alu: est un dossier       # les messages d'erreur sont dans le fichier
$ rm -f erreurs.txt
$ grep tor al* 2> /dev/null     # envoie les erreurs dans la poubelle
ali:ga tor
On peut demander plusieurs redirections :
$ commande -options < fichier0 > fichier1 2> fichier2
idem avec les variantes >>  >|  1>>  1>|  2>>  2>|
3.3. Redirection vers un descripteur
Il est possible de rediriger un descripteur vers le fichier pointé par un autre descripteur, sans repréciser le fichier. La syntaxe est :
a>&ben écriture,a<&ben lecture ;
ceci redirige le descripteur a vers le fichier pointé par le descripteur b.
De cette façon on peut rediriger 2 vers le fichier pointé par 1 :
$ cmd 1> fichier1 2>&1
ou encore rediriger 1 vers le fichier pointé par 2 :
$ cmd 2> fichier2 1>&2
  L'ordre dans lequel on fait les redirections est important :
$ cmd 1> fichier1 2>&1
redirigera 1 vers le fichier1, puis 2 vers le fichier pointé par 1 qui est fichier1 :
alors que
$ cmd 2>&1 1> fichier1
redirigera 2 vers le fichier pointé par 1 qui est le terminal, puis 1 vers le fichier1 :
3.4. Liaison entre 2 commandes avec un tube
Une des possibilités qui a fait la puissance du shell a été de relier la sortie standard d'une commande vers l'entrée standard d'une autre commande.
Le caractère qui permet d'indiquer cela est le | (pipe, ou tube) :
$ cmd1 -options | cmd2 -options
Exemple :
$ ps -aux | grep bash
ps -aux affiche dans le tube la liste de tous les processus,
grep bash lit les lignes dans le tube et affiche celles qui ont le mot bash.
Il est possible d'enchaîner les tubes, on appelle cela un pipeline :
$ cmd1 -options | cmd2 -options | cmd3 -options ...
Voici le diagramme des redirections de ce pipeline :
On peut préciser l'entrée de la première commande et la sortie de la dernière
$ cmd1 -options < fichier1 | ... | cmdn -options > fichiern
En fait on peut rediriger les entrées-sorties de chacune des commandes du pipeline, par exemple :
cmd1 2>> fichier1 | cmd2 2>&1 | cmd3 2> /dev/null
Le diagramme des redirections est alors
Approfondissement
Pour réaliser le pipeline
$ cmd1 | cmd2
que fait bash en interne ?
- 
bash crée un tube (appel de la fonction C
pipe) ; un tube consiste en- un buffer mémoire (généralement de 1M),
 - une position de début et de fin dans le buffer,
 - un descripteur pour écrire dans le buffer (remplir),
 - un descripteur pour lire dans le buffer (vider) ;
 
 - 
bash crée 2 processus (appels C
fork) ; - bash redirige les entrées-sortie des processus sur les descripteurs du 
  tube (appel de la fonction C 
dup2) ; - 
bash recouvre les processus avec les commandes
cmd1etcmd2(appels Cexecvp) ; - 
cmd1écrit dans le tube jusqu'à ce qu'il soit plein (write), puiscmd1est endormi par le système, etcmd2est réveillé ; cmd2lit dans le tube jusqu'à ce qu'il soit vide (read), puiscmd2est endormi par le système, etcmd1est réveillé ;- et ainsi de suite jusqu'à ce que 
cmd1ferme son extrémité du tube (close) ; - 
cmd2continue à lire dans le tube jusqu'à la fin (readrenvoie 0), puis se termine (exit). - 
bash détecte la fin des processus, récupère le code de terminaison et supprime les zombies (
wait) puis affiche le prompt. 
Mécanisme très efficace : bande passante de plusieurs giga-octets par seconde (100 à 1000 fois plus rapide que dans un fichier sur un disque dur).
3.5. Commandes tee et xargs
  La commande tee
La commande tee permet de recopier l'entrée standard à la fois dans un fichier
et sur la sortie standard.
Elle est très utile pour enregistrer dans un fichier ce qui est affiché :
$ cmd1 | tee trace.txt
Elle permet aussi d'enregistrer ce qui passe par un tube :
$ cmd1 | tee trace.txt | cmd2
Exemple :
$ find /etc -name "*.conf" 2> /dev/null | tee res.txt | wc -l
797
$ grep fuse res.txt
/etc/fuse.conf
  La commande xargs
La commande xargs permet de transformer la sortie standard en arguments de la
commande suivante :
$ cmd1 | xargs cmd2
Si la sortie de cmd1 est la chaîne "a b c d", la commande qui sera exécutée 
par xargs sera : cmd2 a b c d
Les options les plus courantes de xargs sont :
-n Xexécute la commande plusieurs fois, par paquet deXarguments-L Yidem par paquet deYlignes-i cmd2 {}exécute la commande pour chaque ligne, désignée par{}-taffiche les commandes effectuées
Exemple avec -n :
$ seq 10 | xargs echo
1 2 3 4 5 6 7 8 9 10
$ seq 10 | xargs echo toto
toto 1 2 3 4 5 6 7 8 9 10
$ seq 10 | xargs -n 3 echo toto
toto 1 2 3
toto 4 5 6
toto 7 8 9
toto 10
Exemple avec -L :
$ echo -e "a b c\nd e f g\ni j"
a b c
d e f g
i j
$ echo -e "a b c\nd e f g\ni j" | xargs echo -e foo
foo a b c d e f g i j
$ echo -e "a b c\nd e f g\ni j" | xargs -L 1 echo foo
foo a b c
foo d e f g
foo i j
$ echo -e "a b c\nd e f g\ni j" | xargs -L 2 echo foo
foo a b c d e f g
foo i j
Exemple avec des fichiers dont le nom contient un espace :
$ mkdir tmp && cd tmp
$ touch essai.txt "mes idées.txt" notes.txt
$ ls *.txt
essai.txt  'mes idées.txt'  notes.txt
$ ls *.txt | cat        # dans un tube, ls affiche un nom par ligne
essai.txt
mes idées.txt
notes.txt
$ ls *.txt | xargs -t -i cp {} {}.old
cp essai.txt essai.txt.old 
cp 'mes idées.txt' 'mes idées.txt.old'
cp notes.txt notes.txt.old 
$ ls -b     # -b échappe les caractères non graphiques
essai.txt  essai.txt.old  mes\ idées.txt  mes\ idées.txt.old  notes.txt 
notes.txt.old
3.6. Commandes sur le contenu
Dans la suite, les arguments optionnels figurent entre [], comme dans les pages
de man. Il ne faut pas recopier les [] en tapant la commande !
  La commande cat
Usage : cat [file]...
Concatène le ou les fichiers ou l'entrée standard et les recopie sur la sortie standard.
$ echo -e "ré\nmi" > f1.txt
$ cat > f2.txt
fa                      # l'utilisateur tape des lignes, lues par cat
sol
^D                      # l'utilisateur tape CTRL D ⟶ fin entrée standard
$ cat f1.txt f2.txt
ré
mi
fa
sol
  La commande wc
Signifie word count.
Usage : wc [-lwc] [file]...
Permet de compter les lignes (-l), les mots (-w) ou les caractères (-c), 
ou par défaut les trois, dans le ou les fichiers ou sur l'entrée standard.
$ ls *.txt | wc -l
4
  La commande tail
Usage : tail [-n nb] [-f] [file]...
Permet de ne sélectionner que les dernières lignes (10 par défaut), du ou des fichiers ou de l'entrée standard.
- Les options principales sont :
 -n nbsélectionne lesnbdernières lignes-n +nbsélectionnes les lignes de la numéronbà la fin-fmet à jour l'affichage chaque fois que le fichier change.
$ tail -n 20 -f /var/log/syslog
  La commande head
Usage : head [-n nb] [file]...
Permet la même chose sur le début du fichier ou l'entrée standard.
$ find /etc -name "*.conf" | head -n 5
  La commande sort
Usage : sort [-u] [-n] [-r] [file]...
Permet de trier (par ordre alphabétique) les lignes du ou des fichiers ou de l'entrée standard.
- Les options principales sont :
 -ules lignes multiples n'apparaissent qu'une fois (unicité)-nle tri est fait sur la valeur numérique du premier mot de chaque ligne-rordre du tri inversé
$ du -sk /usr/* | sort -rn | head -5
  La commande uniq
Usage : uniq [options] file
Recherche et affiche les lignes adjacentes uniques, lues dans le fichier file ou sur l'entrée standard :
- sans option, affiche pour chaque groupe identique la première ligne ;
 - avec 
-u: affiche les lignes adjacentes uniques ; - avec 
-d: n'affiche que les lignes adjacentes multiples, 1 par groupe. 
$ echo -e "ga\nbu\nbu\nzo\nga" | uniq
ga
bu
zo
ga
$ echo -e "ga\nbu\nbu\nzo\nga" | uniq -u
ga
zo
ga
$ echo -e "ga\nbu\nbu\nzo\nga" | uniq -d
bu
  La commande cut
Usage : cut [-c liste] [-d'C' -f liste] [file]...
Permet de ne récupérer que certains caractères ou champs de chaque ligne, dans le ou les fichiers ou sur l'entrée standard.
-c liste: permet de n'afficher que les caractères dont les numéros sont dans la liste.-d'C' -f listeou-d 'C' -f liste: permet de découper chaque ligne avec comme délimiteur le caractèreCet n'afficher que les champs dont les numéros sont dans la liste.liste: sous la formen1oun1,n2...oun1-n2,...
$ echo "13009" | cut -c 1-2
13
$ echo "ga bu zo meu" | cut -d' ' -f 1,3
ga zo
Les éléments sont toujours affichés dans l'ordre lu et une seule fois :
$ echo "ga bu zo meu" | cut -d' ' -f 2,1,4,1
ga bu meu
  La commande tr
Usage : tr [options] set1 [set2]
Permet de transformer un caractère lu sur l'entrée standard en un autre.
set1est une liste de caractères, ou peut être un intervalle par exemplea-z0-9;set2est une autre liste de caractères, de la même taille queset1.
Chaque caractère lu, s'il est dans set1, est remplacé par le caractère
correspondant dans set2.
Options :
-s: remplace les occurrences multiples de caractères dansset1par 1 seul.- -
d: supprime les occurrences de caractères dansset1. 
$ echo "J'ai des idées" | tr a-z A-Z
J'AI DES IDéES
$ echo "J'ai des idées" | tr a-z n-za-m     # rot13
J'nv qrf vqérf
$ echo "J'ai des idées" | tr a-z n-za-m | tr a-z n-za-m
J'ai des idées
$ echo -e "salut\n\n\nles\n\namis" | tr -s '\n'    # supprime lignes vides
salut
les
amis
$ echo "voila, je crois, c'est clair !" | tr -d ',;.!'
voila je crois c'est clair
$ echo "voila, je crois, c'est clair !" | tr -d [:punct:]
voila je crois cest clair 
  La commande grep
(Global search for Regular Expressions and Print)
Usage : grep [options] motif [file]...
Affiche les lignes qui possèdent le motif, lues dans chaque fichier ou sur l'entrée standard.
Le motif est une expression régulière dans laquelle
^désigne le début$désigne la fin.est un caractère quelconque sauf un retour chariot[...]correspond à 1 caractère parmi ceux de la liste*signifie que le caractère peut être présent 0, 1 ou plusieurs fois|associe des motifs alternatifs :motif1|motif2|...
Si le motif comporte des symboles, il faut le protéger avec des ''.
Principales options :
-E: le motif est une expression régulière étendue.-v motif: affiche les lignes qui n'incluent pas le motif.-B n1 -A n2: affichen1lignes avant (before) etn2lignes après (after).
Exemple :
$ grep -E '^[ ]*PS1' -B 1 -A 1 /etc/* 2> /dev/null