From 41deb6ed180587999908e6a459ad21e55bab1f57 Mon Sep 17 00:00:00 2001 From: Robert Alessi Date: Mon, 24 Sep 2018 21:34:02 +0200 Subject: done writing 03-grep-bash.tex --- _preamble.tex | 2 + fichiers/01-ligne-de-commande.tex | 3 +- fichiers/03-grep-bash.tex | 335 ++++++++++++++++++++++++++++++++++---- 3 files changed, 305 insertions(+), 35 deletions(-) diff --git a/_preamble.tex b/_preamble.tex index d71b26d..ba992e0 100644 --- a/_preamble.tex +++ b/_preamble.tex @@ -24,8 +24,10 @@ \usepackage{cleveref} \crefname{table}{tableau}{tableaux} +\usepackage{kalendarium} \usepackage[type={CC}, modifier={by-sa}, version ={3.0}]{doclicense} \author{Robert Alessi} +\date{\KalToday} \lowertitleback{\footnotesize\textcopyright{} 2018 Robert Alessi \mailto[courses]{robert.alessi@cnrs.fr} \doclicenseThis} diff --git a/fichiers/01-ligne-de-commande.tex b/fichiers/01-ligne-de-commande.tex index b4d438f..aaf7db2 100644 --- a/fichiers/01-ligne-de-commande.tex +++ b/fichiers/01-ligne-de-commande.tex @@ -8,11 +8,12 @@ \usepackage{dingbat} \usepackage{mdframed} \mdfsetup{ + everyline, backgroundcolor=Lavender, hidealllines=true} \usepackage{minted} -\surroundwithmdframed{minted} \setminted{ + bgcolor=Lavender, breaklines, breaksymbolright=\small\carriagereturn} \setmintedinline{bgcolor=Lavender} diff --git a/fichiers/03-grep-bash.tex b/fichiers/03-grep-bash.tex index aaf007f..9b3c54a 100644 --- a/fichiers/03-grep-bash.tex +++ b/fichiers/03-grep-bash.tex @@ -6,16 +6,17 @@ \usepackage{units} \usepackage{booktabs} \usepackage{xltabular} -\usepackage{dingbat} \usepackage{mdframed} \mdfsetup{ + everyline, backgroundcolor=Lavender, hidealllines=true} \usepackage{float} +\usepackage{dingbat} \usepackage[newfloat]{minted} \SetupFloatingEnvironment{listing}{listname=Listings} -\surroundwithmdframed{minted} \setminted{ + bgcolor=Lavender, breaklines, breaksymbolright=\small\carriagereturn} \setmintedinline{bgcolor=Lavender} @@ -28,7 +29,10 @@ \maketitle \renewcommand{\contentsname}{Sommaire} \tableofcontents + \listoflistings + +\needspace{3\baselineskip} \listoftables \chapter{grep, les expressions régulières} @@ -352,6 +356,8 @@ art dans le cadre de la programmation en \textsf{WEB}\footnote{\cite{Knuth1983}. Voir également en ligne \url{http://www.literateprogramming.com/}}. +Pour un exemple de code commenté, voir le \vref{lst:copyten}. + \section{Exécution} \label{sec:execution} Il faut ici approfondir la notion de \emph{permissions} sur les @@ -695,7 +701,6 @@ fi Voici donc comment se présente le script \verb|backup.sh| une fois la condition insérée: -\begin{listing}[H] \begin{minted}[linenos,highlightlines={7-14}]{bash} #!/bin/bash echo "Veuillez choisir l'extension des fichiers à sauvegarder" @@ -717,9 +722,8 @@ zip -r "$backupdir".zip "$backupdir" echo "Terminé. $0 a copié $nbre fichiers .$ext dans $backupdir" echo "et l'archive $backupdir.zip a été créée." \end{minted} -\caption{bash: exemple de condition \texttt{if-then-else}} -\label{lst:if-then-else} -\end{listing} +\captionof{listing}{bash: exemple de condition \texttt{if-then-else}% +\label{lst:if-then-else}} \subsection{Conditions en série} \label{sec:conditions-en-serie} @@ -741,7 +745,6 @@ elif [ -e "$backupdir".zip ] \end{minted} Ce qui donne le script \verb|backup.sh| suivant: -\begin{listing}[H] \begin{minted}[linenos,highlightlines={12-17}]{bash} #!/bin/bash echo "Veuillez choisir l'extension des fichiers à sauvegarder" @@ -769,9 +772,7 @@ zip -r "$backupdir".zip "$backupdir" echo "Terminé. $0 a copié $nbre fichiers .$ext dans $backupdir" echo "et l'archive $backupdir.zip a été créée." \end{minted} -\caption{bash: instruction \texttt{elif}} -\label{lst:elif} -\end{listing} +\captionof{listing}{bash: instruction \texttt{elif}\label{lst:elif}} \subsection{Tests} \label{sec:tests} @@ -865,7 +866,6 @@ des opérateurs tels que \verb|{ ... }| Voici un exemple d'indentation d'une structure dans laquelle on a placé une condition à l'intérieur d'une autre condition: -\begin{listing}[H] \begin{minted}[linenos]{bash} #!/bin/bash if [ $1 -gt 10 ] @@ -879,8 +879,7 @@ else echo "Il faut aller au-dessus de 10 pour avoir une réponse!" fi \end{minted} -\caption{bash: exemple d'indentation} -\end{listing} +\captionof{listing}{bash: exemple d'indentation} \subsection{Opérateurs booléens} \label{sec:operateurs-booleens} @@ -937,7 +936,6 @@ esac Le \vref{lst:case} montre un exemple facile à comprendre de cette technique. -\begin{listing}[H] \begin{minted}[linenos]{bash} #!/bin/bash @@ -956,9 +954,7 @@ case $animal in ;; esac \end{minted} -\caption{bash: instruction \texttt{case}} -\label{lst:case} -\end{listing} +\captionof{listing}{bash: instruction \texttt{case}\label{lst:case}} \begin{quoting} \textbf{Commentaire:} \begin{enumerate} @@ -1048,15 +1044,13 @@ La boucle que nous allons utiliser fait appel à trois instructions: Voici maintenant le script qui assure la conversion du format \verb|.tiff| vers le format \verb|.png|: -\begin{listing}[H] \begin{minted}[linenos]{bash} #!/bin/bash for file in $(basename -s .tiff $(ls *.tiff)) do convert "$file".tiff "$file".png done \end{minted} -\caption{bash: \texttt{for ... do ... done}} -\end{listing} +\captionof{listing}{bash: \texttt{for ... do ... done}} \begin{quoting} \textbf{Commentaire:} @@ -1087,7 +1081,8 @@ lignes de code qui suivent aussi longtemps qu'un test donné retourne un résultat positif (\enquote{vrai}, en anglais \emph{true}). Le script \verb|countlines.sh|, donné dans le \cref{lst:countlines} ci-dessous, utilise cette expression pour compter les lignes des -fichiers. +fichiers\footnote{Une autre façon plus simple d'écrire le même + programme, voir le \vref{lst:countlines-mk2}.}. \begin{minted}[linenos,highlightlines={13,16-17}]{bash} #!/bin/bash @@ -1101,7 +1096,7 @@ if [ ! -e $file ] || [ -z $file ] echo "Erreur: le fichier $file n'existe pas." exit 1 else - while read line + while read -r line # 'let' permet de poser des opérations arithmétiques; # à la place, on aurait pu écrire: do ((++numline)) do let "numline = numline + 1" @@ -1128,6 +1123,16 @@ en question était donc constituée d'une saisie au clavier dans laquelle la ligne était formée par une chaîne de caractères terminée par un \emph{retour charriot} (\emph{carriage return}). +\begin{mdframed}[backgroundcolor=Cyan] + \verb|read| admet aussi une option \verb|-r| qui est importante: + quand cette option est activée, le caractère \verb|\| + (\emph{backslash}) est traité comme un caractère ordinaire, et non + comme un caractère actif. Pour simplement compter les lignes d'un + fichier, il faut ajouter cette option car en \emph{bash} le + \emph{backslash} est précisément un caractère actif: à la fin d'une + ligne, il sert à joindre cette ligne à la ligne suivante. +\end{mdframed} + Étudions de près les lignes~13--17 du \cref{lst:countlines}: l'instruction \verb|while| (l.~13) se termine à la ligne~17 par \verb|done|. Et aussitôt à ce moment, @@ -1141,14 +1146,14 @@ la boucle \verb|while ... done|. \item À la ligne~6, on crée une variable \verb|numline| à laquelle on attribue la valeur \verb|0|. Elle servira donc de compteur. \item L'instruction essentielle est à la ligne~13: - \mintinline{bash}|while read line|: comme ce qui suit \verb|while| - \emph{est un test}, ce test donnera un résultat positif aussi - longtemps que la variable \verb|line| existe, c'est-à-dire aussi - longtemps que l'opérateur de redirection \mintinline{bash}|<| de la - ligne~17 envoie des lignes terminées par un retour charriot. Tant - que cette condition est remplie, la commande de la ligne~16 sera - exécutée, et le compteur de lignes sera incrémenté d'une unité à - chaque fois. + \mintinline{bash}|while read -r line|: comme ce qui suit + \verb|while| \emph{est un test}, ce test donnera un résultat positif + aussi longtemps que la variable \verb|line| existe, c'est-à-dire + aussi longtemps que l'opérateur de redirection \mintinline{bash}|<| + de la ligne~17 envoie des lignes terminées par un retour + charriot. Tant que cette condition est remplie, la commande de la + ligne~16 sera exécutée, et le compteur de lignes sera incrémenté + d'une unité à chaque fois. \item Les instructions des lignes~20--25 sont faciles à suivre. Étudiez-les à l'aide du \vref{tab:tests}: vous pourrez comprendre comment la programmation peut être adaptée pour suivre @@ -1164,14 +1169,276 @@ Erreur: le fichier whack n'existe pas. [robert@kiddo courses]$ ./countlines.sh Entrez le nom du fichier dont vous voulez compter les lignes: Fichier: makefile -Votre fichier makefile compte 17 lignes. +Votre fichier makefile compte 21 lignes. +\end{minted} + +\paragraph{until} +\index[cmds]{until|textbf}À la différence de \verb|while|, +\verb|until| exécute les instructions qui suivent jusqu'au moment où +le résultat du test associé à \verb|until| devient \emph{positif} +(\emph{true}). Pour prendre un exemple très simple, le script suivant, +que l'on appellera \verb|roar.sh|, demande combien de fois on souhaite +tirer la queue d'un lion: +\begin{minted}[linenos]{bash} +#!/bin/bash + +read -p 'Combien de fois tirez-vous la queue du lion? ' rahtimes + +# Définition du compteurs de rugissements: +rah=1 + +until [ $rah -gt $rahtimes ] +do + echo "Raaaaaaaaahhhhhhhhhhhh! ($rah)" + sleep 1 + ((++rah)) +done +\end{minted} +\captionof{listing}{bash: comment faire rugir le lion?} + +\begin{quoting} + \textbf{Commentaire:} + \begin{enumerate} + \item La condition posée à la ligne~8 se comprend ainsi: + \enquote{faites ce qui suit jusqu'à ce que le compteurs de + rugissements atteingne une valeur supérieure à celle définie par + l'utilisateur. Si la valeur est supérieure, sortez de la boucle.} +\item À la ligne~11, on demande à \emph{bash} d'attendre une seconde. +\item À la ligne~12, on incrémente de 1 la valeur du compteur de + rugissements (voir ci-dessus le \vref{lst:countlines}, l.~15), puis + on reprend la boucle à la ligne~8. + \end{enumerate} +\end{quoting} + +Exécution du script \verb|roar.sh|: +\begin{minted}{text} +[robert@kiddo courses]$ ./roar.sh +Combien de fois tirez-vous la queue du lion? 3 +Raaaaaaaaahhhhhhhhhhhh! (1) +Raaaaaaaaahhhhhhhhhhhh! (2) +Raaaaaaaaahhhhhhhhhhhh! (3) +[robert@kiddo courses]$ +\end{minted} + +\paragraph{break} +\index[cmds]{break|textbf} \verb|break| est une instruction qui +ordonne de quitter immédiatement la boucle dans laquelle on se +trouve. Supposons par exemple que l'on écrive un programme dans lequel +on souhaite limiter une action telle que la copie de +fichiers. L'instruction \verb|break| sera exécutée dès que la limite +est atteinte. Appelons ce script \verb|copyten.sh|: +\begin{minted}[linenos]{bash} +#!/bin/bash + +# création du compteur de fichiers copiés. +countfiles=0 + +# On demande quels fichiers doivent être copiés. Mais avant cela, on +# explique à l'utilisateur ce que fait ce programme. +echo "Attention: ce programme copie au maximum 10 fichiers." +read -p 'Que souhaitez-vous copier: ' files + +# On demande la destination: +read -p 'Répertoire de destination: ' dest + +# doit être un répertoire: +if [ ! -d $dest ] +then + echo "Erreur: la destination doit être un répertoire." + echo " Le cas échéant, utilisez \"mkdir $dest\"" + echo " pour créer le répertoire de destination." + exit 1 +else # Si est un répertoire, alors pour chaque fichier + # copié on incrémente le compteur. Et dès que le compteur + # atteint le chiffre de 10, on sort de la boucle. + for file in $files # pour chaque fichier à copier + do + cp $file $dest + let "countfiles = countfiles + 1" + if [ $countfiles -eq 10 ] + then + break # sortie de la boucle + fi + done +fi + +echo "Terminé. 10 fichiers au maximum ont été copiés dans $dest." +\end{minted} +\captionof{listing}{bash: copie d'un nombre limité de + fichiers\label{lst:copyten}} + +Ce script donne un exemple de code commenté. Comme on le voit, les +commentaires peuvent se trouver sur des lignes isolées aussi bien que +sur des lignes qui contiennent des commandes\footnote{Voir ci-dessus, + \vref{sec:les-commentaires}.}. + +Exécution du script \verb|copyten.sh|: +\begin{minted}{text} +[robert@kiddo courses]$ ls *.txt +01.txt 03.txt 05.txt 07.txt 09.txt 11.txt +02.txt 04.txt 06.txt 08.txt 10.txt 12.txt +[robert@kiddo courses]$ ./copyten.sh +Attention: ce programme copie au maximum 10 fichiers. +Que souhaitez-vous copier: *.txt +Répertoire de destination: Houba +Erreur: la destination doit être un répertoire. + Le cas échéant, utilisez "mkdir Houba" + pour créer le répertoire de destination. +[robert@kiddo courses]$ mkdir Houba +[robert@kiddo courses]$ ./copyten.sh +Attention: ce programme copie au maximum 10 fichiers. +Que souhaitez-vous copier: *.txt +Répertoire de destination: Houba +Terminé. 10 fichiers au maximum ont été copiés dans Houba. +[robert@kiddo courses]$ ls Houba/ +01.txt 02.txt 03.txt 04.txt 05.txt 06.txt 07.txt +08.txt 09.txt 10.txt +\end{minted} + +\paragraph{continue} +\index[cmds]{continue|textbf} À l'inverse de \verb|break|, +\verb|continue| demande à \emph{bash} d'interrompre l'itération +courante mais sans quitter la boucle, puis de reprendre la boucle à +partir de l'itération suivante. C'est une façon de prévoir des +exceptions. Par exemple, nous pouvons modifier le script +\ref{lst:copyten} comme suit: + +\begin{minted}[linenos,highlightlines={26-31}]{bash} +#!/bin/bash + +# création du compteur de fichiers copiés. +countfiles=0 + +# On demande quels fichiers doivent être copiés. Mais avant cela, on +# explique à l'utilisateur ce que fait ce programme. +echo "Attention: ce programme copie au maximum 10 fichiers." +read -p 'Que souhaitez-vous copier: ' files + +# On demande la destination: +read -p 'Répertoire de destination: ' dest + +# doit être un répertoire: +if [ ! -d $dest ] +then + echo "Erreur: la destination doit être un répertoire." + echo " Le cas échéant, utilisez \"mkdir $dest\"" + echo " pour créer le répertoire de destination." + exit 1 +else # Si est un répertoire, alors pour chaque fichier + # copié on incrémente le compteur. Et dès que le compteur + # atteint le chiffre de 10, on sort de la boucle. + for file in $files # pour chaque fichier à copier + do + if [ ! -e $file ] # si le fichier à copier n'exite pas + then + echo "création de $file qui n'existe pas..." + touch $dest/$file + continue # arrêter ici et reprendre à la l. 24 + fi + cp $file $dest + let "countfiles = countfiles + 1" + if [ $countfiles -eq 10 ] + then + break # sortie de la boucle + fi + done +fi + +echo "Terminé. 10 fichiers au maximum ont été copiés dans $dest." +\end{minted} +\captionof{listing}{bash: copie d'un nombre limité de + fichiers sans échec si le fichier source n'existe pas} + +\begin{quoting} + \textbf{Commentaire:} + \begin{enumerate} + \item À la ligne~30, l'instruction \verb|continue| intervient dans + le cas où le fichier à copier n'existe pas (voir le test de la + ligne~26). + \item Dans ce cas, le fichier est créé par la ligne~28. + \item Puis \verb|continue| interrompt la boucle et la reprend depuis + la ligne~24. + \end{enumerate} +\end{quoting} + +Voici ce que donne l'exécution de ce script: +\begin{minted}{text} +[robert@kiddo courses]$ ./copyten.sh +Attention: ce programme copie au maximum 10 fichiers. +Que souhaitez-vous copier: tchic.txt +Répertoire de destination: Houba +création de tchic.txt qui n'existe pas... +Terminé. 10 fichiers au maximum ont été copiés dans Houba. +[robert@kiddo courses]$ ls Houba/ +tchic.txt +\end{minted} + +\section{Les fonctions} +\label{sec:les-fonctions} +Comme leur nom l'indique, les fonctions permettent d'exécuter des +instructions de façon autonome dans un script. Elles peuvent être +ensuite utilisées aussi souvent que nécessaire et permettent donc de +réduire la taille du script. Deux formats sont permis: +\begin{minted}[linenos]{bash} +# Format 1 +ma_fonction () { + +} + +# Format 2 +function ma_fonction { + +} +\end{minted} + +Ces deux formats sont strictement équivalents. Le premier est le plus +répandu car il rappelle ce qui se fait dans de nombreux autres +langages où l'on utilise les parenthèses pour passer aux fonctions des +variables, des chaînes de caractères, des paramètres optionnels ou +même d'autres fonctions. Toutefois, en \emph{bash}, on ne met jamais +rien entre les parenthèses qui sont purement décoratives. + +Le script suivant permet de parvenir au même résultat que le script +qui a été présenté dans le \vref{lst:countlines}: +\begin{minted}[linenos]{bash} +#!/bin/bash + +echo "Entrez le nom du fichier dont vous voulez compter les lignes:" +read -p 'Fichier: ' file + +countlines () { + cat $1 | wc -l +} + +if [ ! -e $file ] || [ -z $file ] + then + echo "Erreur: le fichier $file n'existe pas." + exit 1 + else + numline=$(countlines $file) +fi + +if [ $numline -le 1 ] + then + echo "Votre fichier $file compte $numline ligne." + else + echo "Votre fichier $file compte $numline lignes." +fi \end{minted} +\captionof{listing}{bash: exemple de + fonction\label{lst:countlines-mk2}} +Pour terminer, exécutons cette nouvelle version de notre script +ici appelée \verb|countlines-mk2.sh|: + +\begin{minted}{text} +[robert@kiddo courses]$ ./countlines-mk2.sh +Entrez le nom du fichier dont vous voulez compter les lignes: +Fichier: makefile +Votre fichier makefile compte 21 lignes. +\end{minted} \hfill\verb|../..| à suivre \printindex[cmds] \end{document} - -\item \verb|<| lit le contenu du fichier dont le nom suit et le passe - en argument à la commande qui précède pour traitement. \ No newline at end of file -- cgit v1.2.3