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>&b
en écriture,a<&b
en 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
cmd1
etcmd2
(appels Cexecvp
) ; -
cmd1
écrit dans le tube jusqu'à ce qu'il soit plein (write
), puiscmd1
est endormi par le système, etcmd2
est réveillé ; cmd2
lit dans le tube jusqu'à ce qu'il soit vide (read
), puiscmd2
est endormi par le système, etcmd1
est réveillé ;- et ainsi de suite jusqu'à ce que
cmd1
ferme son extrémité du tube (close
) ; -
cmd2
continue à lire dans le tube jusqu'à la fin (read
renvoie 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 X
exécute la commande plusieurs fois, par paquet deX
arguments-L Y
idem par paquet deY
lignes-i cmd2 {}
exécute la commande pour chaque ligne, désignée par{}
-t
affiche 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 nb
dernières lignes, ou 10 par défaut,
du ou des fichiers ou de l'entrée standard.
-f
met à 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 -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 :
-u
les lignes multiples n'apparaissent qu'une fois (unicité)-n
le tri est fait sur la valeur numérique du premier mot de chaque ligne-r
ordre 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 liste
ou-d 'C' -f liste
: permet de découper chaque ligne avec comme délimiteur le caractèreC
et n'afficher que les champs dont les numéros sont dans la liste.liste
: sous la formen1
oun1,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.
set1
est une liste de caractères, ou peut être un intervalle par exemplea-z0-9
;set2
est 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 dansset1
par 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
: affichen1
lignes avant (before) etn2
lignes après (after).
Exemple :
$ grep -E '^[ ]*PS1' -B 1 -A 1 /etc/* 2> /dev/null