Bash Scripting

et commandes “avancées”

8. Personnaliser son environnement

8. Personnaliser son environnement

Variables d’envionnement

Lorsque vous êtes dans un shell, il existe des variables d’environnement qui définissent certains comportements.

Par exemple, la variable ‘HOME’ contient /home/padawan et corresponds à l’endroit où cd retourne par défaut (si pas de dossier donné en argument)

Autre exemples :

SHELL : /bin/bash (généralement)
LANG, LC_ALL, ... : langue utilisée par les messages
USER, USERNAME : nom d'utilisateur

8. Personnaliser son environnement

Changer une variable d’envionnement

Exemple :

HOME=/tmp/

Lister les variables d’envionnement

env permet de lister les variables d’environnement

$ env
LC_ALL=en_US.UTF-8
HOME=/home/alex
LC_MONETARY=fr_FR.UTF-8
TERM=rxvt-unicode-256color
[...]

8. Personnaliser son environnement

Définir des aliases

Un alias est un nom “custom” pour une commande et des options

alias ll='ls -l'
alias rm='rm -i'
alias ls='ls --color=auto'

On peut connaître les alias existants avec juste alias

(Mauvaise blague : définir alias cd='rm -r' !)

8. Personnaliser son environnement

Les fichiers de profil

  • Le fichier ~/.bashrc est lu à chaque lancement de shell
  • Il permet de définir des commandes à lancer à ce moment
  • Par exemple, des alias à définir ou des variables à changer…
  • Pour appliquer les modifications, il faut faire source ~/.bashrc

Autres fichiers de profils : ~/.profile et /etc/bash_profile

9. Commandes avancées

9.1 - Redirections, assemblages

9.1 - Redirections, assemblages

Schema fonctionnel d’une commande

  • Une commande est une boîte avec des entrées / sorties
  • et un code de retour ($?)
    • 0 : tout s’est bien passé
    • 1 (ou toute valeur différente de 0) : problème !

9.1 - Redirections, assemblages

Entrées / sorties

  • arguments : donnés lors du lancement de la commande (ex: /usr/ dans ls /usr/)
  • stdin : flux d’entrée (typ. viens du clavier)
  • stdout : flux de sortie (typ. vers le terminal)
  • stderr : flux d’erreur (typ. vers le terminal aussi !)

9.1 - Redirections, assemblages

Code de retour

$ ls /toto
ls: cannot access '/toto': No such file or directory
$ echo $?
2

9.1 - Redirections, assemblages

Rediriger les entrées/sorties (1/3)

  • cmd > fichier : renvoie stdout vers un fichier (le fichier sera d’abord écrasé !)
  • cmd >> fichier : ajoute stdout à la suite du fichier
  • cmd < fichier : utiliser ‘fichier’ comme stdin pour la commande
  • cmd <<< "chaine" : utiliser ‘chaine" comme stdin pour la commande

Exemples

ls -la ~/ > tous_mes_fichiers.txt  # Sauvegarde la liste de tous les fichiers dans le home
echo "manger" >> todo.txt          # Ajoute "manger" a la liste des choses à faire
wc < "une grande phrase"           # Compte le nomde de mot d'une chaine

9.1 - Redirections, assemblages

Rediriger les entrées/sorties (2/3)

  • commande 2> fichier : renvoie stderr vers un fichier (le fichier sera d’abord écrasé !)
  • commande 2>&1 : renvoie stderr vers stdout !

Exemples :

ls /* 2> errors # Sauvegarde les erreurs dans 'errors'
ls /* 2>&1 > log # Redirige les erreurs vers stdout (la console) et stdout vers 'log'
ls /* > log 2>&1 # Redirige tout vers 'log' !

9.1 - Redirections, assemblages

Rediriger les entrées/sorties (3/3)

Fichiers speciaux :

  • /dev/null : puit sans fond (trou noir)
  • /dev/urandom : generateur aleatoire (trou blanc)

9.1 - Redirections, assemblages

Rediriger les entrées/sorties (3/3)

Fichiers speciaux :

  • /dev/null : puit sans fond (trou noir)
  • /dev/urandom : generateur aleatoire (trou blanc)
ls /* 2> /dev/null           # Ignore stderr
mv ./todo.txt /dev/null      # Façon originale de supprimer un fichier !
head -c 5 < /dev/urandom     # Affiche 5 caractères de /dev/urandom
cat /dev/urandom > /dev/null # Injecte de l'aleatoire dans le puit sans fond

9.1 - Redirections, assemblages

Assembler des commandes

Executer plusieurs commandes à la suite :

  • cmd1; cmd2 : execute cmd1 puis cmd2
  • cmd1 && cmd2 : execute cmd1 puis cmd2 mais seulement si cmd1 reussie !
  • cmd1 || cmd2 : execute cmd1 puis cmd2 mais seulement si cmd1 a échoué
  • cmd1 && (cmd2; cmd3) : “groupe” cmd2 et cmd3 ensemble

Exercice en live :

que fait cmd1 && cmd2 || cmd3

9. Commandes avancées

9.2 - Pipes et boîte à outils

Pipes ! (1/3)

  • cmd1 | cmd2 permet d’assembler des commandes de sorte à ce que le stdout de cmd1 devienne le stdin de cmd2 !

Exemple : cat /etc/login.defs | head -n 3

  • (Attention, par défaut stderr n’est pas affecté par les pipes !)

Pipes ! (2/3)

Lorsqu’on utilise des pipes, c’est generalement pour enchaîner des opérations comme :

  • générer ou récupérer des données
  • filtrer ces données
  • modifier ces données à la volée

Pipes ! (3/3)

Precisions techniques

  • La transmission d’une commande à l’autre se fait “en temps réel”. La première commande n’a pas besoin d’être terminée pour que la deuxieme commence à travailler.
  • Si la deuxieme commande a terminée, la première peut être terminée prématurément (SIGPIPE).
    • C’est le cas par exemple pour cat tres_gros_fichier | head -n 3

Boîte à outils : tee

tee permet de rediriger stdout vers un fichier tout en l’affichant quand meme dans la console

tree ~/documents | tee arbo_docs.txt  # Affiche et enregistre l'arborescence de ~/documents
openssl speed | tee -a tests.log      # Affiche et ajoute la sortie de openssl à la suite de tests.log

Boîte à outils : grep (1/3)

grep permet de trouver des lignes qui contiennent un mot clef (ou plus generalement, une expression)

$ ls -l | grep r2d2
-rw-r--r--  1 alex alex        0 Oct  2 20:31 r2d2.conf
-rw-r--r--  1 r2d2 alex     1219 Jan  6  2018 zblorf.scd
$ cat /etc/login.defs | grep TIMEOUT
LOGIN_TIMEOUT		60

(on aurait aussi pu simplement faire : grep TIMEOUT /etc/login.defs)

Boîte à outils : grep (2/3)

Une option utile (parmis d’autres) : -v permet d’inverser le filtre

$ ls -l | grep -v "alex alex"
total 158376
d---rwxr-x  2 alex droid    4096 Oct  2 15:48 droidplace
-rw-r--r--  1 r2d2 alex     1219 Jan  6  2018 zblorf.scd

On peut créer un “ou” avec : r2d2\|c3p0

$ ps -ef | grep "alex\|r2d2"
# Affiche seulement les lignes contenant alex ou r2d2

Boîte à outils : grep (3/3)

On peut faire référence à des débuts ou fin de ligne avec ^ et $ :

$ cat /etc/os-release | grep "^ID"
ID=manjaro

$ ps -ef | grep "bash$"
alex      5411   956  0 Oct02 pts/13   00:00:00 -bash
alex      5794   956  0 Oct02 pts/14   00:00:00 -bash
alex      6164   956  0 Oct02 pts/15   00:00:00 -bash
root      6222  6218  0 Oct02 pts/15   00:00:00 bash

10. Bash scripts

10. Bash scripts

10.0 Écrire et executer des scripts

10.0 Écrire / executer

Des scripts

  • bash (/bin/bash) est un interpreteur
  • Plutôt que de faire de l’interactif, on peut écrire une suite d’instruction qu’il doit executer (un script)
  • Un script peut être considéré comme un type de programme, caractérisé par le fait qu’il reste de taille modeste

10.0 Écrire / executer

Utilité des scripts bash

Ce que ça ne fait généralement pas :

  • du calcul scientifique
  • des interfaces graphiques / web
  • des manipulations ‘fines’ d’information

Ce que ça fait plutôt bien :

  • prototypage rapide
  • automatisation de tâches d’administration (fichiers, commandes, ..)
  • rendre des tâches parametrables ou interactives

10.0 Écrire / executer

Ecrire un script (1/2)

#!/bin/bash

# Un commentaire
cmd1
cmd2
cmd3
...

exit 0    # (Optionnel, 0 par defaut)

10.0 Écrire / executer

Ecrire un script (2/2)

#!/bin/bash

echo "Hello, world !"
echo "How are you today ?"

10.0 Écrire / executer

exit

  • exit permet d’interrompre le script immédiatement
  • exit 0 quitte et signale que tout s’est bien passé
  • exit 1 (ou une valeur différente de 0) quitte et signale un problème

10.0 Écrire / executer

Executer un script (1/3)

Première façon : avec l’interpreteur bash

  • bash script.sh execute script.sh dans un processus à part
  • on annonce explicitement qu’il s’agit d’un script bash
    • dans l’absolu, pas besoin d’avoir mis #!/bin/bash

10.0 Écrire / exécuter

Exécuter un script (2/3)

Deuxième façon : avec source

  • source script.sh execute le script dans le terminal en cours
  • 95% du temps, ce n’est pas source qu’il faut utiliser pour votre cas d’usage !
  • Cas d’usage typique de source : recharger le .bashrc
  • (Autre cas : source venv/bin/activate pour les virtualenv python)

10.0 Écrire / exécuter

Exécuter un script (3/3)

Troisième façon : en donnant les permissions d’execution à votre script

chmod +x script.sh   # À faire la première fois seulement
./script.sh
  • l’interpreteur utilisé sera implicitement celui défini après le #! à la première ligne
  • (dans notre cas : #!/bin/bash)

10.0 Écrire / executer

Parenthèse sur la variable PATH (1/2)

La variable d’environnement PATH définit où aller chercher les programmes

$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/sbin

$ which ls
/usr/bin/ls

$ which script.sh
which: no script.sh in (/usr/local/bin:/usr/bin:/bin:/usr/local/sbin

10.0 Écrire / executer

Parenthèse sur la variable PATH (2/2)

$ ./script.sh  # Fonctionnera (si +x activé)
$ script.sh    # Ne fonctionnera a priori pas

Néanmoins il est possible d’ajouter des dossiers à PATH :

PATH="$PATH:/home/padawan/my_programs/"

Ensuite, vous pourrez utiliser depuis n’importe où les programmes dans ~/my_programs !

10.0 Écrire / executer

Résumé

  • bash script.sh est la manière “explicite” de lancer un script bash
  • ./script.sh lance un executable (+x) via un chemin absolu ou relatif
  • source script.sh execute le code dans le shell en cours !
  • script.sh peut être utilisé seulement si le script est dans un des dossier de PATH

10. Bash scripts

10.1 Les variables

10.1 Les variables

De manière générale, une variable est :

  • un contenant pour une information
  • une façon de donner un nom à cette information

Initialiser une variable en bash (attention à la syntaxe) :

PI="3.1415"

Utiliser une variable :

echo "Pi vaut (environ) $PI"

N.B. : différence contenu/contenant sans trop d’ambiguité

10.1 Les variables

On peut modifier une variable existante :

$ HOME="/home/alex"
$ HOME="/var/log"

10.1 Les variables

Initialiser une variable à partir du résultat d’une autre commande

NB_DE_LIGNES=$(wc -l < /etc/login.defs)

Syntaxe équivalente avec des backquotes (ou backticks) (historique, dépréciée)

NB_DE_LIGNES=`wc -l < /etc/login.defs`

10.1 Les variables

On peut également initialiser une variable en composant avec d’autres variables :

MY_HOME="/home/$USER"

ou encore :

FICHIER="/etc/login.defs"
NB_DE_LIGNES=$(wc -l < $FICHIER)
MESSAGE="Il y a $NB_DE_LIGNES lignes dans $FICHIER"
echo "$MESSAGE"

10.1 Les variables

Notes diverses (1/5)

  • En bash, on manipule du texte !
$ PI="3.14"

$ NOMBRE="$PI+2"

$ echo $NOMBRE
3.14+2           # littéralement !

10.1 Les variables

Notes diverses (2/5)

  • Lorsqu’on utilise une variable, il faut mieux l’entourer de quotes :
$ FICHIER="document signé.pdf"

$ ls -l $FICHIER
ls: cannot access 'document': No such file or directory
ls: cannot access 'signé.pdf': No such file or directory

$ ls -l "$FICHIER"
-rw-r--r-- 1 alex alex 106814 Mar  2  2018 'document signé.pdf'

10. Bash scripts

10.2 Paramétrabilité / interactivité

10.2 Paramétrabilité / interactivité

  • Le comportement d’un script peut être paramétré via des options ou des données en argument
  • On peut également créer de l’interactivité, c’est à dire demander des informations à l’utilisateur pendant l’exécution du programme

10.2 Paramétrabilité / interactivité

Les paramètres

  • $0 contient le nom du script
  • $1 contient le premier argument
  • $2 contient le deuxieme argument
  • et ainsi de suite …
  • $# contient le nombre d’arguments total
  • $@ corresponds à “tous les arguments” (en un seul bloc)

10.2 Paramétrabilité / interactivité

#!/bin/bash

echo "Ce script s'apelle $0 et a eu $# arguments"
echo "Le premier argument est : $1"
echo "Le deuxieme argument est : $2"
$ ./monscript.sh coucou "les gens"
Ce script s'apelle monscript.sh et a eu 2 arguments
Le premier argument est : coucou
Le deuxieme argument est : les gens

10.2 Paramétrabilité / interactivité

Interactivité

Il est possible d’attendre une entrée de l’utilisateur avec read :

echo -n "Comment tu t'appelles ? "
read NAME
echo "OK, bonjour $NAME !"