Download SLIDE-C02-Scripting-FR.pdf
Download C02-Scripting-FR.pdf
Script
Qu'est-ce qu'un script
Au lieu de lancer les commandes directement dans un terminal, on peut écrire un fichier texte avec le shebang et les droits d'exécution
username@hostname:~$ cat myfirstscript.sh
#!/bin/bash
echo toto
username@hostname:~$ chmod +x myfirstscript.sh
username@hostname:~$ ./myfirstscript.sh
toto
Avantages désavantages
- Avantages
- Plus lisible
- Enregistré
- Exportable
- Débogage
- Désavantages
- Débogage
Variable d'un script
| Nom | Description |
|---|---|
| $0 | le nom du programme shell courant. |
| $1…${n} | les n paramètres passés au programme (au shell) lors de son appel. |
| $# | le nombre de paramètres passés à l'appel du programme shell (sans inclure le paramètre $0) |
| $* | la liste des paramètres passés à l'appel du programme shell (sans le paramètre $0) |
| $$ | le numéro du processus courant (il y a un numéro unique par processus sur la machine) |
| $? | le code d'erreur de la dernière commande exécutée. |
Exemple d'utilisation
username@hostname:~$ cat mysecondscript.sh
#!/bin/bash
echo "Thx to launch ${0}"
echo "There are ${#} arguments"
echo "They are : ${*} but the second is $2"
false
echo ${?}
username@hostname:~$ ./mysecondscript.sh toto titi tutu
Thx to launch ./mysecondscript.sh
There are 3 arguments
They are : toto titi tutu but the second is titi
1
Kit de survie
Règles d'or
- Indentez votre script
- Commentez votre script
- Utilisez une règle de nommage
- Déclarez votre variable au début de votre script
- Toujours tester vos entrées
- Donnez à votre script un peu "d'air frais"
- Testez la valeur de retour de vos commandes SHELL ($?)
- Utilisez le man , niveau 1 (essayez un man -k)
- Rendez votre script exécutable :
chmod +x Monnouveauscript.sh
Exemple de règles d'or 1/2
#BAD
if [[ -f $titi ]];then echo "your parameter is a file";cp $1 "$1".old;fi
#GOOD
if [[ -f ${Nom_Fichier_Saisi} ]]
then
echo "your parameter is a file"
cp $1 "${Nom_Fichier_Saisi}".old
fi
Exemple de règles d'or 2/2
si votre script attend un argument représentant un nom de fichier.
#Test of arguments
if [ $# -lt 1 ]
then
echo "You must give an argument for the script"
exit 1
fi
#Test of the type of the first argument
if [ -e $1 ]
then
echo "You must give an valid file name for the first argument for the script"
exit 2
fi
Algo
SI Condition
Condition IF
THEN
------> Launch_action
END IF
Exemple de condition if
username@hostname:~$ cat exampleIf.sh
#!/bin/bash
if [ $1 -eq 1 ]
then
echo "The first argument is 1"
fi
username@hostname:~$ bash exampleIf.sh 2
username@hostname:~$ bash exampleIf.sh 1
The first argument is 1
condition si/sinon
Condition IF
THEN
------> Launch_action
ELSE
------> Launch_action
END IF
Exemple de condition if/else
username@hostname:~$ cat exampleIfElse.sh
#!/bin/bash
if [ $1 -eq 1 ]
then
echo "The first argument is 1"
else
echo "The first argument is not 1"
fi
username@hostname:~$ exempleIfElse.sh 2
The first argument is not 1
username@hostname:~$ exempleIfElse.sh 1
The first argument is 1
condition if/elif
Condition IF
THEN
------> Launch_action
ELSE IF other_condition
THEN
------> Launch_action
END IF
Exemple de condition if/elif
username@hostname:~$ exampleIfelIf.sh
#!/bin/bash
if [ $1 -eq 1 ]
then
echo "The first argument is 1"
elif [ $1 -eq 2 ]
then
echo "The first argument is 2"
fi
username@hostname:~$ exampleIfelIf.sh 10
username@hostname:~$ exampleIfelIf.sh 1
The first argument is 1
username@hostname:~$ exampleIfelIf.sh 2
The first argument is 2
condition if/elif/else
Condition IF
THEN
------> Launch_action
ELSE IF other_condition
THEN
------> Launch_action
ELSE
------> Launch_action
END IF
Exemple de condition if/elif/else
username@hostname:~$ exampleIfelIfElse.sh
#!/bin/bash
if [ $1 -eq 1 ]
then
echo "The first argument is 1"
elif [ $1 -eq 2 ]
then
echo "The first argument is 2"
else
echo "I do not understant"
fi
username@hostname:~$ exampleIfelIfElse.sh 10
I do not understant
username@hostname:~$ exampleIfelIfElse.sh 1
The first argument is 1
username@hostname:~$ exampleIfelIfElse.sh 2
The first argument is 2
Tests
Pour connaître tous les tests possibles man test
Les plus courantes :
- \"\$chaine1\" = \"\$chaine2\" --> Les 2 chaînes sont identiques
- \"\$chaine1\" != \"\$chaine2\" --> Les 2 chaînes ne sont pas identiques
- -z \"\$chaine\" --> La chaîne est vide
- -n \"\$chaine\" --> La chaîne n'est pas vide
- \"\$entier1\" -eq \"\$entier2\" --> Les 2 nombres sont égaux
- \"\$entier1\" -ne \"\$entier2\" --> Les 2 nombres sont différents
- \"\$entier1\" -le \"\$entier2\" --> entier1 <= entier2
- \"\$entier1\" -lt \"\$entier2\" --> entier1 < entier2
- \"\$entier1\" -ge \"\$entier2\" --> entier1 >= entier2
- \"\$entier1\" -gt \"\$entier2\" --> entier1 > entier2
- -e \"\$file\" --> Le fichier existe
Règles de comparaison 1/3
Opérandes de fichier
| Opérande | Description | exemple |
|---|---|---|
| -e nomfichier | true si le nom de fichier existe | [ -e /etc/shadow ] |
| -d nomfichier | true si le nom du fichier est un répertoire | [ -d /tmp/trash ] |
| -f nomfichier | true si le nom du fichier est un fichier ordinaire | [ -f /tmp/Log.txt ] |
| -L nomfichier | true si le nom du fichier est un lien symbolique | [ -L /home ] |
| -r nomfichier | true si le nom du fichier est lisible (r) | [ -r /boot/vmlinuz ] |
| -w nomfichier | true si le nom du fichier est modifiable (w) | [ -w /var/log ] |
| -x nomfichier | true si le nom du fichier est un exécutable (x) | [ -x /sbin/halt ] |
Règles de comparaison 2/3
Opérandes de chaîne
| Opérande | Description | exemple |
|---|---|---|
| -z chaine | vrai si la chaîne est vide | [ -z "${VAR}"] |
| -n chaine | vrai si la chaîne n'est PAS vide | [ -n "${VAR}"] |
| chaine1 == chaine2 | vrai si les deux chaînes sont égales | [ "${VAR}" == "toto" ] |
| chaine1 = chaine2 | vrai si les deux chaînes sont égales | [ "${VAR}" = "toto" ] |
| chaine1 != chaine2 | vrai si les deux chaînes ne sont PAS égales | [ "${VAR}" != "toto" ] |
Règles de comparaison 3/3
Opérandes numériques
| Opérande | Description | exemple |
|---|---|---|
| num1 -eq num2 | égalité | [ $Nombre -eq 42 ] |
| num1 -ne num2 | pas égal | [ $Number -ne 42 ] |
| num1 -lt num2 | inférieur à (<) | [ $Nombre -lt 42 ] |
| num1 -le num2 | inférieur ou égal (<=) | [ $Nombre -le 42 ] |
| num1 -gt num2 | supérieur à (>) | [ $Number -gt 42 ] |
| num1 -ge num2 | supérieur ou égal (>=) | [ $Number -ge 42 ] |
Exemple de test (1/2)
#!/bin/bash
# directory exists ? 1/2
test -d /home/user
rc=$?
if [ $rc -ne 0 ]
then
echo "The directory /home/user does not exist"
fi
Exemple de test (2/2)
#!/bin/bash
# directory exists ? 2/2
if [ -d "/home/user" ]
then
echo "the directory /home/user exists"
fi
# comparison of 2 strings
if [ "toto" = "titi" ]
then
echo "toto is not equal to titi"
fi
Boucle tant que
Condition WHILE
DO
------> Launch_action
END DO
Exemple de boucle while (1/2)
username@hostname:~$ while.sh
#!/bin/bash
a=0
while [ $a -le 3 ]
do
echo '$a'
a=$(( $a + 1 ))
done
username@hostname:~$ while.sh
0
1
2
3
Exemple de boucle while (2/2)
while true
do
echo $RANDOM
done
Le bash est compilé en tant que monothread 64 bits. Avec cette commande, votre bash utilisera 100 % d'un cœur de processeur. Pour protéger votre CPU, mettez toujours une action "inutile/time-out"
while true
do
echo $RANDOM
sleep 1
done
pour la boucle
FOR variable IN value1 value2 value3
DO
------> Launch_action
END DO
Exemple de boucle for (1/2)
username@hostname:~$ for1.sh
#!/bin/bash
for var in 'value1' 'value2' 'value3'
do
echo "Var = ${var}" ;
done
username@hostname:~$ for1.sh
Var = value1
Var = value2
Var = value3
Exemple de boucle for (2/2)
Pour se rapprocher du code C (cette syntaxe est peu utilisée en bash) :
username@hostname:~$ for2.sh
#!/bin/bash
for i in $(seq 0 2)
do
echo $i
done
username@hostname:~$ for2.sh
0
1
2
Cette syntaxe $(seq 0 3) est équivalente à ((i=0;i<=3;i++))
Case/Esac
case ${vars} in
1) command1
command1bis
;;
2) command2
command2bis
;;
*) commanddefault
commanddefault2
;;
esac
Exemple de Cas/Esac
username@hostname:~$ myScriptCase.sh
#!/bin/bash
case ${1} in
toto) echo "toto is a beautifull name";;
titi) echo "I prefer toto as a name";;
*) echo "i do not understand"
esac
username@hostname:~$myScriptCase.sh toto
toto is a beautifull name
username@hostname:~$myScriptCase.sh titi
I prefer toto as a name
username@hostname:~$myScriptCase.sh Loic
i do not understand
ARRÊTER/CONTINUER
username@hostname:~$ for3.sh
#!/bin/bash
for var in value1 value2 value3 value4 value5
do
[ "$var" = "value2" ] && continue
[ "$var" = "value4" ] && break
echo $var
done
username@hostname:~$ for3.sh
value1
value3
BREAK = arrêter la boucle
CONTINUE = passer à l'itération suivante
La gestion des processus
Linux étant un système multitâche, plusieurs programmes peuvent s'exécuter en même temps.
Lorsqu'un programme est démarré, un processus est créé. C'est une entité active qui possède des caractéristiques (priorité, registres, compteur ordinal, mémoire, etc.). Certaines caractéristiques peuvent changer avec le temps
Le système identifie les processus à l'aide d'un identifiant (PID u003d Pprocess IDentification).
La gestion des processus sous Linux est dite hiérarchique.
Un processus peut lui-même créer un autre processus (fork + exec). Le processus créé est appelé un processus enfant. Le créateur est appelé le processus parent.
nice et renice
Les commandes nice et renice vous permettent de définir ou de modifier la priorité d'un processus. La plage de valeurs possibles va de -20 (priorité la plus favorable) à 19 (la moins favorable).
username@hostname:~$ nice -n -20 find / -type f -name "*.sh"
username@hostname:~$ renice 20 7643
kill
La commande kill envoie un signal à un processus. Des "superpositions" à la commande kill existent killall, pgrep / pkill, xkill
username@hostname:~$ kill 456
username@hostname:~$ kill -9 -1
username@hostname:~$ pkill firefox
Gestion des tâches dans une session interactive
Les processus interactifs sont démarrés et gérés à partir du terminal de l'utilisateur. Il existe 2 modes :
-
Mode premier plan
-
Mode arrière-plan
Mode premier plan
Le processus monopolise le terminal jusqu'à sa terminaison
username@hostname:~$ sleep 10
[...]
Mode arrière-plan
Le processus fonctionne en parallèle avec le terminal
username@hostname:~$ sleep 10 &
[1] 3384
$
La séquence de touches "ctrl-z" et les commandes "jobs, bg, fg commands" permettent de faire basculer un processus d'un mode à l'autre.

Afficher les processus
Vous pouvez utiliser la commande SHELL ps pour afficher tous les processus en cours d'exécution sur votre ordinateur
exemple pour voir les processus appartenant à votre SHELL actuel :
username@hostname:~$ ps
3837 pts/2 00:00:00 bash
137967 pts/2 00:00:09 evince
144605 pts/2 00:00:00 ps
exemple pour voir les processus vous appartenant actuel propriétaire :
username@hostname:~$ ps -u username
PID TTY TIME CMD
2053 ? 00:00:02 systemd
2054 ? 00:00:00 (sd-pam)
2059 ? 00:04:16 pulseaudio
....
Comment avoir un code source élégant
Le code de retour
Il faut contrôler le code de retour ($?). Dans une fonction, il faut utiliser la commande return <ReturnCode>, et dans la fonction principale il faut utiliser la commande exit <ReturnCode>.
Attention, la commande return quitte immédiatement la fonction. La commande exit termine le script (même si elle est utilisée dans une fonction).
Vérifiez vos entrées
Quelle que soit la façon dont les données d'entrée sont récupérées, elles doivent toujours être vérifiées.
- si un fichier doit être lu, il faut déjà savoir s'il existe
- si vous devez faire une opération arithmétique, il faut vérifier que ce sont bien des nombres (attention à la division par 0)
- ...
Beaucoup de vérifications existent dans la commande test (voir les règles de comparaison).
Indentation
Préférez-vous ce code :
function action () { echo -ne "${1}\t";shift;${*};rc=${?};\
[ ${rc} -eq 0 ] && echo '[OK]' || \
echo '[KO]';return ${rc};}
ou celui-ci ?
function action () {
echo -ne "${1}\t"
shift
${*}
rc=${?}
[ ${rc} -eq 0 ] && echo '[OK]' || echo '[KO]'
return ${rc}
}
Je préfère le second script. L'indentation est une question de goût. Mais elle doit au moins être homogène dans tout le script. Pensez à aérer votre code (une ligne vide ne coûte rien, mais rend le code plus lisible).
Commentaires
Ajoutez beaucoup de commentaires dans votre script. Pourquoi ?
- si vous reprenez votre code après 6 mois, vous le comprendrez plus facilement
- si vous donnez votre code à quelqu'un d'autre, il le comprendra plus facilement
- l'utilisateur de votre code comprendra plus facilement les erreurs
- ...# Construction de Script
Tous les projets en environnement de test / production sont basés sur des exigences.
Ces exigences sont nécessaires pour s'assurer que la création finale fait ce que nous/ils attendent.
Exigences
Ce script a pour but de classer les anciens élèves présents lors d'une réunion.
Ici, nous allons créer un script avec ces exigences :
-
Le nom du script est : alumni-reunion.sh
-
Le script doit analyser un fichier csv passé en premier argument
-
Le format du fichier csv est : NOM;PRENOM;ANNEE;NIVEAU (chemin du fichier : /data/admin/list/student-list)
-
Pour chaque ligne du fichier csv, le script doit demander : "PRENOM NOM est présent ? (y/n)"
-
La réponse doit être y ou n et il ne faut pas utiliser la touche Entrée pour valider
-
Le script doit créer un dossier avec la date (ex : /data/admin/result/2022-09-27)
-
À chaque réponse y ou n, il faut ajouter dans le premier argument un nouveau fichier (chemin : /data/admin/result/YYYY-MM-DD/)
-
Les fichiers de résultats sont triés par groupe [année][niveau] (ex : /data/admin/result/YYYY-MM-DD/student-list_2020-M1)
-
Le format du contenu des fichiers est : NOM;PRENOM;ANNEE;NIVEAU;[present|absent]
-
Le script se termine par un résumé de tous les fichiers créés et le total des présents/absents (avec un en-tête : FICHIER | présent | absent |)
Algorithme

Fonctions Classiques
Les fonctions classiques nécessaires dans le script sont les suivantes :
-
Check ou Action pour vérifier chaque commande
-
Help ou Usage pour afficher les informations sur le script
-
ArgCheck pour vérifier l'argument ou le type d'argument
Fonctions Spécifiques
Pour chaque script, il faut analyser les exigences pour les traduire en fonctions ou en code bash.
-
LineToVar : traduit chaque colonne d'une ligne en une variable spécifique (Nom=[...] Prenom=[...])
-
Question : pose à l'utilisateur la question "PRENOM NOM est présent ? (y/n)" et affiche le résultat sur la sortie standard de la fonction
-
NameFileOutput : crée la variable du fichier de sortie /data/admin/result/student-list_ANNEE-NIVEAU avec les données de LineToVar et le résultat de Question
-
Resume : affiche tous les fichiers créés avec le total des présents/absents (ex : FICHIER : 12 2)
Sortie
Sortie (Premier lancement)
user@pem ~ $ ./alumni-reunion.sh list-student.csv
* Création de l'environnement /data/admin/result/2022-09-28 : OK
KADE Anthony est présent ? (y/n) : y
LILIAN Giles est présent ? (y/n) : y
[...]
ASIA Petty est présent ? (y/n) : n
FICHIER | présent | absent
-------------------------------------------------------------
student-list_2013-M2 | 0 | 1
student-list_2018-M2 | 1 | 0
student-list_2020-M2 | 1 | 0
-------------------------------------------------------------
TOTAL | 2 | 1
Sortie (relance)
user@pem ~ $ ./alumni-reunion.sh /data/admin/list/student-list
/data/admin/result/2022-09-28 existe \
voulez-vous continuer (supprimer toutes les données) (y/n) : y
* Nettoyage de l'environnement : OK
KADE Anthony est présent ? (y/n) : y
LILIAN Giles est présent ? (y/n) : y
[...]
ASIA Petty est présent ? (y/n) : n
FICHIER | présent | absent
-------------------------------------------------------------
student-list_2013-M2 | 0 | 1
student-list_2018-M2 | 1 | 0
student-list_2020-M2 | 1 | 0
-------------------------------------------------------------
TOTAL | 2 | 1
Fonction
RAPPEL : TOUTES les fonctions doivent être en haut du script avant le main !!!
Help
La fonction Help sert uniquement à afficher les informations et à quitter. Si quelque chose ne va pas, vous pouvez utiliser cette fonction pour quitter le script.
# Print the help and exit
function Help() {
echo "$(basename $0) [absolute or relative path file]"
[[ ! -z $1 ]] && [[ $(let $1) ]] && Exit=$1 || Exit=0
exit ${Exit}
}
Action
La fonction Action prend 2 arguments :
- ce qu'il faut afficher
- la commande à exécuter (pas de stdout/stderr)
# Print info exec and status
function Action () {
# Print the first arguement without \n in the end (-n)
echo -ne "\n\* $1 : "
# Shift to the left
shift
# execute all the argument like a classic command but redirect in /dev/null
$* &> /dev/null
ResultExec=$?
# Check the result and print OK/Failed
if [[ ${ResultExec} -eq 0 ]]
then
echo OK
else
echo Failed; Help ${ResultExec}
fi
}
Check
Vous pouvez utiliser Check ou Action mais Check s'utilise différemment.
function Check() {
HaveToExit=$2
[[ ${HaveToExit} -eq 1 ]] && $Help ${ResultExec}
if [[ $1 -eq 0 ]]
then
echo OK
else
echo Failed
Help $1
fi
}
# Exemple :
echo -n 'Is it OK ? : '
true
Check $? 0
ArgCheck
Vérifie l'environnement :
- le premier argument est-il un fichier
- le dossier de sortie existe-t-il
- la création du dossier de sortie est-elle OK
function ArgCheck() {
# Check the first arg of the script and directory output data
[[ ! -f $1 ]] && echo "$1 is not a file" && Help 1
if [[ -d ${DirOutput} ]]; then
while [[ $Qans != "y" ]] && [[ $Qans != "n" ]]
do
echo -e "\n"
read -p "${DirOutput} exist \
do you want to continue (delete all data) (y/n) : " -n1 Qans
done
# Clean environement
[[ $Qans == "n" ]] && exit || \
Action "Clean environement" "1" rm -rf ${DirOutput}/*
fi
}
NameFileOutput
Crée la variable qui contient le nom du fichier de sortie pour chaque ligne du fichier d'entrée
# Create the varname of the output file
function NameFileOutput(){
FileName=student-list_${1}-${2}
echo ${DirOutput}/${FileName}
}
Question
Pour chaque ligne du fichier d'entrée, il faut poser la question présent/absent
function Question() {
qName=$1
qSurname=$2
Answer=""
Result=""
# Check if the data is y or n
while [[ -z ${Result} ]]
do
read -p "$Name $Surname is present ? (y/n) : " \
-n1 Answer </dev/tty
[[ ${Answer} == "y" ]] && Result=present
[[ ${Answer} == "n" ]] && Result=absent
done
echo $Result
}
LineToVar
Analyse tout le fichier, récupère les données et appelle les autres fonctions
# Analyse for all line
function LineToVar(){
while read -r Line
do
echo -e "\n"
# Gen variable environement for each line
Name=$(echo $Line | cut -d";" -f1)
Surname=$(echo $Line | cut -d";" -f2)
Year=$(echo $Line | cut -d";" -f3)
Level=$(echo $Line | cut -d";" -f4)
Result=$(Question "${Name}" "${Surname}")
OutputFile=$(NameFileOutput "${Year}" "${Level}")
# output data in the outputfile
echo "${Name};${Surname};${Year};${Level};${Result}" >> ${OutputFile}
done < $1
}
Resume
Affiche le résumé de tous les fichiers de sortie créés
function Resume() {
echo -e "\n\nFILE\t\t\t|\tpresent\t|\tabsent"
echo "-------------------------------------------------------------"
# find all output file
for FileOutput in $(find ${DirOutput} -type f \
-name "student-list_*")
do
# Gen variable for each file
FileName=$(basename $FileOutput)
Present=$(cat ${FileOutput} | grep present|wc -l)
Absent=$(cat ${FileOutput} | grep absent|wc -l)
TotPresent=$((TotPresent+Present))
TotAbsent=$((TotAbsent+Absent))
echo -e "$FileName\t|\t${Present}\t|\t$Absent"
done
echo "-------------------------------------------------------------"
# print total
echo -e "TOTAL\t\t\t|\t${TotPresent}\t|\t$TotAbsent"
}
Main
Main appelle les fonctions et crée des variables pour tout le script et les fonctions
######## MAIN ########
Date=$(date "+%Y-%m-%d")
DirOutput=/data/admin/result/${Date}
ArgCheck $1
[[ ! -d ${DirOutput} ]] && \
Action "Create environement ${DirOutput}" "1" mkdir -p ${DirOutput}
LineToVar $1
Resume
Fichier principal et fonctions
Vous pouvez séparer le fichier principal et toutes les fonctions avec source
#!/bin/bash
source $(realpath $(dirname $0))/fct_classic
source $(realpath $(dirname $0))/fct_specific
ArgCheck $1
[[ ! -d ${DirOutput} ]] && \
Action "Create environement ${DirOutput}" "1" mkdir -p ${DirOutput}
LineToVar $1
Resume
Math
Maths dans le Bash
Les opérations arithmétiques en bash ne peuvent être effectuées que sur des nombres entiers.
$(( INT OPERATION_TYPE INT))
# Ex 1: simple addition
username@hostname:~$ echo $(( 2 + 2 ))
4
username@hostname:~$ foo=$(( 2 + 2 ))
username@hostname:~$ echo $foo
4
username@hostname:~$ echo $(( $foo + 2 ))
6
username@hostname:~$ echo $(( foo + 2 ))
6
Math types d'opérations dans Bash
Les types d'opérations sont :
-
addition : '+'
-
soustraction :
- -
multiplication :
* -
division :
/
Arrondi en mathématiques bash
bash arrondit le résultat des opérations "vers le bas" pour obtenir un entier
username@hostname:~$ echo $(( 9 / 3 ))
3
username@hostname:~$ echo $(( 10 / 3 ))
3
username@hostname:~$ echo $(( 11 / 3 ))
3
username@hostname:~$ echo $(( 12 / 3 ))
4
bash / maths / bc
Si vous devez effectuer une opération arithmétique avec float, vous avez besoin de bc avec son option scale :
La syntaxe est la suivante :
username@hostname:~$ echo "scale=3;10/3" | bc
3.333
username@hostname:~$ echo "scale=2;10/3" | bc
3.33
username@hostname:~$ echo "scale=1;10/3" | bc
3.3
Séquences
Parfois, il est utile de générer une séquence d'entiers d'un début à un point final.
Vous pouvez utiliser la commande seq pour le faire.
Exemple :
username@hostname:~$ seq 1 10
1
2
3
4
5
6
7
8
9
10
Les flux
Chaque processus comporte 3 flux :
- le flux d'entrée "stdin"
- le flux de sortie standard "stdout"
- le flux de sortie d'erreur "stderr"

sortie standard
C'est le flux le plus visible. Il sera affiche à l'écran.
Il est possible de :
- l'envoyer dans un nouveau fichier :
cmd > file - l'envoyer à la fin d'un fichier :
cmd >> file -
l'envoyer à une autre commande :
cmd1 | cmd2 -
Dans ce dernier cas, le stdout de cmd1 sera le stdin de cmd2
commandes de chaînage
Avec ce dernier exemple vous pouvez "composer" une commande complexe en enchaînant plusieurs commandes simples. Exemple :
username@hostname:~$ echo -e "totontatantitintito" >>File.txt
username@hostname:~$ cat File.txt
toto
tata
titi
tito
username@hostname:~$ cat File.txt | grep "to"
toto
tito
username@hostname:~$ cat File.txt | grep "to" | wc -l
2
stderr
C'est le flux que le terminal affiche lors d'une erreur. Pour ce flux il est possible de :
- l'envoyer dans un nouveau fichier :
cmd 2> file - l'envoyer à la fin d'un fichier :
cmd 2>> file -
l'envoyez vers stdout :
cmd 2>&1 > fileoucmd &> file -
Donc dans ce dernier cas, l'ensemble de stderr et stdout sera dans file
stdin (exemple 1/2)
Il s'agit d'un flux invisible mais très utile.
Prenons par exemple le cas suivant : recherchez les lignes contenant foo
username@hostname:~$ cat liste.txt
# it displays the contents of list.txt
username@hostname:~$ cat liste.txt | grep foo
# it only prints the line containing foo
username@hostname:~$ cat liste.txt | grep ma_chaine > liste_filtre.txt
Ainsi la commande grep aura dans son stdin le contenu de list.txt, et elle pourra faire son traitement.
stdin (exemple 2/2)
Autre exemple de stdin : lire progressivement depuis le clavier
username@hostname:~$ sort << ENDSORT
> toto
> titi
> tata
> ENDSORT
tata
titi
toto
Le terminal attendra du texte et tant que la chaine de caractères est différente du mot-clé (ici ENDSORT), vous pouvez continuer.
Dès que la chaine ENDSORT est détecté, toutes les données seront envoyées à sort .
Le résultat sort sera envoyé dans sa sortie standard. On peut modifier le stdout :
username@hostname:~$ sort << ENDSORT > my_new_file_sort_from_keyboard
stderr (exemple)
username@hostname:~$ ls
File
Directory
username@hostname:~$ cat FileNotExist
cat: FileNotExist: No such file or directory
username@hostname:~$ cat FileNotExist 2> ./stderr.txt
username@hostname:~$ cat FileNotExist 2> ./stderr.txt 1> ./stdout.txt
username@hostname:~$ ls
File
Directory
stderr.txt
stdout.txt
username@hostname:~$ cat stderr.txt
cat: FileNotExist: No such file or directory
username@hostname:~$ cat stdout.txt
username@hostname:~$
ReGex
Les différents types
Il existe 2 types d'expressions régulières :
- expressions régulières basiques (vi, grep, expr, sed) : ERb
- expressions régulières étendues (grep -e, egrep, awk) : ERe
Les mots-clés des regex
- ^ = Début de ligne
- $ = Fin de ligne
- . = N'importe quel caractère
- [liste_de_caractères] = Un caractère parmi ceux listés
- [^liste_de_caractères] = Un caractère qui n'est pas dans la liste
- * = 0 à n fois le caractère ou le groupe précédent
- \ = Protection d'un caractère spécial
- PATERN{n} = Nombre de répétitions du motif (ERe)
- (PATERN) = Groupe (ERe)
Exemple de ReGex (1/3)
Prenons ce fichier texte comme exemple :
toto likes titi
Isen 2021
Toto likes titi
Trouver les lignes qui commencent par toto et se terminent par titi
user@pem: cat exampleRegex.txt
toto likes titi
Isen 2021
Toto likes titi
user@pem: grep "^toto.*titi$" exampleRegex.txt
toto likes titi
Exemple de ReGex (2/3)
Trouver les lignes qui commencent par une majuscule
user@pem: cat exampleRegex.txt
toto likes titi
Isen 2021
Toto likes titi
user@pem: grep "^[A-Z]" exampleRegex.txt
Isen 2021
Toto likes titi
Exemple de ReGex (3/3)
Trouver les lignes qui contiennent "to" 2 fois
user@pem: cat exampleRegex.txt
toto likes titi
Isen 2021
Toto likes titi
user@pem: grep -E "(to){2}" exampleRegex.txt
toto likes titi
```# SED
TODO: en -> fr
## Introduction
SED is a command that allows manipulation of text file from regular expression
By default sed displays the result in the stdout. To do the action directly in the file you need the option **-i**
## Substitution
Change one patern by another
```sed "s/PATERN_TO_LOOK_FOR/REPLACEMENT_PATTERN/"```
```bash
user@pem: cat exampleRegex.txt
toto likes titi
Isen 2021
Toto likes titi
user@pem: sed -e "s/titi/loic/" exampleRegex.txt
toto likes loic
Isen 2021
Toto likes loic
Insert
Add a line before the wanted patern
sed "/PATERN_TO_LOOK_FOR/iPATERN_TO_ADD/"
user@pem: cat exampleRegex.txt
toto likes titi
Isen 2021
Toto likes titi
user@pem: sed -e "/Toto/iTiti" exampleRegex.txt
toto likes titi
Isen 2021
Titi
Toto likes titi
Append
Add a line after the wanted patern
sed "/PATERN_TO_LOOK_FOR/aPATERN_TO_ADD/"
user@pem: cat exampleRegex.txt
toto likes titi
Isen 2021
Toto likes titi
user@pem: sed -e "/toto/aTiti" exampleRegex.txt
toto likes titi
Titi
Isen 2021
Toto likes titi
Delete
Delete a line containing a pattern.
sed "/PATERN/d"
user@pem: cat exampleRegex.txt
toto likes titi
Isen 2021
Toto likes titi
user@pem: sed -e "/titi$/d" exampleRegex.txt
Isen 2021