5 - bash (suite)

Combiner les commandes avec bash

Les Entrées/Sorties d’une commande

Chaque commande agit comme un hachoir qui prendrait une carotte en entrée et sortirait des carottes râpées.

Une commande a une entrée standard, généralement ce qui est saisi au clavier et une sortie standard, généralement l’écran et est numérotée 1.

Une commande peut aussi générer des messages d’erreur (ex: permission non accordée), ces messages sont affichés sur la sortie d’erreur standard qui est aussi généralement l’écran et est numérotée 2.

Chaque commande a donc:

  • Une entrée standard : STDIN

  • Une sortie standard : STDOUT numérotée 1

  • Une sortie d’erreur standard : STDERR numérotée 2

HTTP

Exemple:

$ find / -name services

Il est possible de modifier ces entrées/sorties grâce à des redirections.

UtilisationExplicationAide visuelle
> fichier redirige stdout pour écraser un fichier
>> fichier redirige stdout pour l'ajouter à un fichier
2> fichier redirige stderr pour écraser un fichier
&> fichier redirige stdout et stderr pour écraser le même fichier
&>> fichier redirige stdout et stderr pour les ajouter au même fichier
2> /dev/null supprime les messages d'erreur stderr en les redirigeant vers /dev/null

Si on souhaite envoyer le résultat de la commande de la commande dans un fichier plutôt que de l’envoyer à l’écran STDOUT, il faudra rediriger la sortie standard vers un fichier:

$ find / -name services 1>resultat.txt

Ou

$ find / -name services >resultat.txt

Remarquez que les erreurs s’affichent toujours à l’écran. Il est possible de se débarrasser des erreurs en redirigeant la sortie d’erreur standard STDERR :

$ find / -name services 2>/dev/null

/dev/null agit comme un trou noir dans lequel tout ce qu’on envoie disparait.

Il est possible de rediriger la sortie standard et la sortie d’erreur standard:

$ find / -name services >resultats.txt 2>/dev/null

Il est aussi possible de rediriger la sortie d’erreur standard vers la sortie standard et d’envoyer le tout dans un fichier:

$ find / -name services >resultats.txt 2>&1

Remarquez que, dans les commandes précédentes, la redirection > écrit dans un fichier mais écrase ce qu’il contenait avant.

Exemple:

$ ls -l /etc > ~/etc.txt

Suivi de :

$ ls /etc > ~/etc.txt

Que contient le fichier etc.txt? Il contient juste le résultat de la 2ème commande.

Si je veux ajouter le contenu de la 2ème commande au fichier etc.txt sans effacer son contenu, il faudra modifier la 2ème commande pour mettre:

$ ls /etc >> ~/etc.txt

La majorité des commandes ont besoin d’une information en entrée sur laquelle travailler.

Par défaut, la commande lit cette information sur STDIN, c’est-à-dire les informations venant du clavier mais il est possible de changer ça de deux façons:

Redirection de l’entrée standard STDIN : <

En récupérant la sortie standard d’une autre commande (vu plus loin) grâce à un tube (pipe) : |

Nous ne verrons pas la redirection à l’aide de <.

Exercices 1

  1. Sans être root et sans utiliser sudo, rechercher le fichier services sur tout le disque dur.
  • Est-ce facile de le trouver dans la sortie de la commande?
  1. Faites la même recherche mais en redirigeant les lignes “Accès refusé” vers le fichier /dev/null.
  • Est-ce plus facile de trouver le résultat de la commande?

  • Sauvegardez le résultat dans le fichier ~/services.txt à l’aide d’une redirection.

Le |

Le |, se prononce pipe (à l’anglaise).

Il permet de récupérer la sortie standard STDOUT d’une commande et la passer à l’entrée standard STDIN d’une autre commande.

HTTP

La sortie standard STDOUT représente l’affichage à l’écran.

L’entrée standard STDIN est ce dont la commande a besoin pour travailler.

Le | permet de chainer des commandes.

La 2ème commande récupère le résultat de la 1ère commande pour travailler dessus.

Le nombre de commandes que l’on peut ainsi enchainer n’a pas de limite.

Exemple:

$ cat /etc/services

Que se passe-t-il? Avez-vous le temps de tout lire?

Nous voudrions avoir le temps de lire :

$ cat /etc/services | more

Ou même pouvoir naviguer dans le fichier:

$ cat /etc/services | less

Mais nous voulions seulement ce qui concerne ssh.

$ cat /etc/services | grep ssh

Ou seulement ce qui concerne le port 22

$ cat /etc/services | grep ssh | grep 22

Les filtres

Enchainer des commandes permet d’appliquer de nombreux filtres sur le résultat d’une commande:

Commande Résutats
cat fichier.txt | wc -l Compte le nombre de lignes du fichier (wc : word count, -l pour les lignes)
cat fichier | grep [-iv] recherche Permet de garder (ou éliminer -v) les lignes contenant la recherche, sans tenir compte des majuscules -i.
find / -name “*.conf” | sort classe le résultat de la commande find par ordre alphabétique.
cat /etc/passwd | sed “s/root/admin/" Remplace root par admin dans l’affichage (pas dans le fichier)
cat /etc/passwd | cut -d: -f1 | sort Affiche uniquement le 1er champs de chaque ligne du fichier /etc/passwd en utilisant : comme séparateur de champs et les classe par ordre alphabétique.

Il existe de nombreuses autres commandes permettant de modifier la sortie d’une commande:

  • Remplace les A par des a
$ tr 'A' 'a'
  • Enlève les doublons
$ uniq
  • Permet de mettre côte à côte les colonnes de plusieurs fichiers
$ join

Exemple:

$ cat types.txt
1 Protéines
2 Glucides
3 Gras

$ cat nourriture.txt
1 Fromage 
2 Patates
3 Beurre


$ join types nourriture.txt
1 Protéines Fromage
2 Glucides Patates
3 Gras Beurre
  • Autre exemple:
$ echo $PATH | tr ':' '\n' | sort

Prend le contenu de la variable $PATH, remplace les : par un retour à la ligne (\n) et les classe par ordre alphbétique.

Exercices 2

En utilisant le | et les filtres, trouvez le numéro de port de zephyr-srv dans le fichier /etc/services.

Dans le fichier /etc/services, combien y a-t-il de lignes qui ne contiennent pas de e?

Et combien de lignes ne contiennent ni e ni a?

La boucle while

La boucle while permet de traiter le résultat d’une commande ligne par ligne.

Un traitement peut être effectué sur chacune des lignes.

En reprenant l’exemple précédent, si on souhaite connaitre la taille de chacun des répertoires qui composent la variable $PATH (du -sh rep : permet de connaitre la taille du répertoire).

$ echo $PATH | tr ':' '\n' | while read i; do du -sh $i; done

La commande while récupère la sortie de la commande tr et la lit ligne par ligne.

Chaque ligne correspond donc à un répertoire de la variable $PATH.

Pour chaque répertoire, on exécute la commande du -sh qui permet de connaitre la taille du répertoire.

Exercices 3

  1. Recherchez tous les fichiers de configuration du système (on considère qu’ils se terminent par .conf) puis n’affichez que le nom du fichier sans le chemin.
  • La commande basename /rep1/rep2/…/fichier.txt affiche seulement fichier.txt.

  • Une fois l’exercice terminé, classez les résultats par ordre alphabétique.

  1. Avec une boucle while, parcourez le fichier /etc/services et pour chaque ligne, ne garder que le 1er champs en utilisant comme délimiteur ‘ ’ (espace).
  • Une fois terminé, éliminez les doublons et comptez le nombre de lignes.