Systèmes informatiques
Fermer ×

Scripts shell linux

Structure d'un script

Shell linux

Le shell linux ou unix est un interpréteur de commande qui fait office d’interface entre l’utilisateur ou le programme d’application et le système d’exploitation.

Il existe différents shell :

Le shell comprend :

Le fichier script

Le script shell est une suite de commandes shell écrites dans un fichier texte qui commence par une ligne particulière :

#!/bin/sh
Cette ligne commence par deux caractères spéciaux "#!" suivi de chemin absolu de la commande qui permet de lancer l'interpréteur comme ici sh pour le shell par défaut du système. La commande sh est, en général, un lien symbolique vers l'interpréteur de commande du système qui est souvent soit bash soit dash. La commande suivante permet le type de cette commande sh :
ls -l /bin/sh

La commande ls permet d'afficher la liste des fichiers, ici, avec l'option -l, elle permet d'afficher les informations du fichier /bin/sh et faire apparaître le fichier lié à ce lien symbolique.

Une ligne qui commence seulement par le caractère # est une ligne de commentaire qui ne sera pas interprétée.

Plusieurs commandes peuvent être écrite sur la même ligne en les séparant par un point-virgule.

Exécution d'un script

Fichier exécutable

L'extension du fichier peut être .sh pour signifier qu'il s'agit d'un script shell, mais elle n'est pas obligatoire. De plus le fichier doit être rendu exécutable au moins par le propriétaire avec la commande :

chmod u+x nomfichier

Accès au programme

Pour que l'interpréteur de commande trouve le fichier de script, il doit être dans un répertoire présent dans la variable d'environnement PATH. Cette variable précise l'ensemble des répertoires qui contiennent des programmes, comme le contenu de cette variable PATH :

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

L'ordre d'écriture des répertoires représente l'ordre de recherche de la commande.

La commande which, suivie du nom de la commande, permet de vérifier si cette commande est accessible par le PATH.

Exemple

which ls
/usr/bin/ls

Si le fichier de script n'est pas dans un des répertoires du PATH, il faut lui préciser le chemin absolu ou relatif afin que l'interpréteur de commande puisse l'exécuter.

Le chemin absolu représente l'ensemble des répertoires depuis la racine de l'arborescence et commence par le caractère /.

Le chemin relatif commence au répertoire courant en utilisant éventuellement ".." pour "remonter" dans la l'arborescence.

Exemple :

On a une commande monscript.sh dans le répertoire /home/utilisateur/messcripts/, pour exécuter cette commande dans /home/utilisateur/mesdonnees/, en utilisant le chemin relatif, il faut écrire :

../messcripts/monscript.sh

et en utilisant le chemin absolu, il faut écrire :

/home/utilisateur/messcripts/monscript.sh

Les différents shell

Très souvent plusieurs shell sont installés sur la machine afin de permettre aux utilisateurs de pouvoir choisir. Mais les shells ne sont pas entièrement compatible, ce qui est les cas de bash qui, contrairement à dash, ne respectent pas entièrement la norme POSIX. Ce qui a pour conséquence que certaines syntaxes qui fonctionnent avec bash ne fonctionnent pas avec dash. Cela prend toute son importance lorsque la console utilise bash et que le lien symbolique sh est dirigé vers dash, comme cela est le cas sur les distributions basées sur debian. La conséquence est qu'une syntaxe peut fonctionner dans la console et ne plus fonctionner dans le script shell.

Ceci peut être vérifier très simplement, en éditant le fichier /etc/password, en cherchant la ligne qui correspond à l'utilisateur. Sur ligne on lire, par exemple "/bin/bash", ce qui signifie que l'interpréteur de commande fonctionne avec bash. Ensuite on utilise la commande ls -l sh pour faire apparaître le nom de la commande qui est liée à sh et qui peut être dash. On a donc des scripts qui risquent de fonctionner avec dash et un interpréteur qui fonctionne avec bash. La solution est soit d'écrire un script compatible dash ce qui le rend portable, ou bien de changer la première ligne du script en remplaçant sh par bash.

Exemple de commandes pour détecter le shell utilisé par la console :

cat /etc/passwd | grep $USER | cut -d ':' -f 7

Exemple de commande pour détecter la commande liée à la commande sh

ls -l /bin/sh | cut -d '>' -f 2

L'explication de ces lignes de commandes sera fournie dans les paragraphes qui suivent.

Les variables d'environnement

Définition et utilisation

Ce sont les variables utilisées dans les scripts shell. Elle sont définies par une suite de caractères majuscules, minuscules et éventuellement le caractère "_". L'espace, les caractères de ponctuation qui sont souvent des séparateurs (:) ou des caractères de contrôle (!) ne doivent jamais être utilisés. Il est très important de noté que l'espace est un séparateur de paramètres dans une commande shell.

On affecte une valeur à une variable d'environnement avec le symbole =. L'affectation ne doit pas contenir d'espaces autour du symbole égal. Si la valeur contient des espaces, il est conseillé de la mettre en guillemets.

Exemple d'affectation :

MONSITE="le site perga.fr"

Pour utiliser le contenu d'une variable d'environnement, il faut la précéder du symbole $ et éventuellement l'encadrer entre accolades.

Exemple d'utilisation

echo "${MONSITE}"

ou encore

echo "$MONSITE"

La version sans accolades est à éviter car elle peut quelques fois être source d'erreur d'interprétation.

Portée des variables d'environnement

Une variable d'environnement est accessible uniquement dans le script dans lequel elle a été affectée. Lorsque le script est terminé, ses variables d'environnement ne sont pas transmises à l'interpréteur de commande, ou, plus généralement au processus père.

Si l'on veut que les variables d'environnement soient transmises à l'interpréteur de commande, il faut exécuter le script en le précédant de la commande source suivi d'un espace ou bien d'un point suivi d'un espace, exemple :

source ../messcripts/monscript.sh

ou bien

. ../messcripts/monscript.sh

Cette commande transmet l'ensemble des variables d'environnement, pour ne pas transmettre une variable d'environnement il suffit de la supprimer avec la commande unset NOMVARIAVLE où NOMVARIABLE est la nom de la variable d'environnement sans le symbole $.

De même pour transmettre une variable d'environnement au processus fils qui peut être un autre script, il faut précéder la variable d'environnement sans le symbole $ de la commande export.

Le traitement des variables d'environnement

En exprimant la variable d'environnement entre accolades avec des paramètres complémentaires, on peut extraire certaines informations relatives au contenu ou bien encore effectuer un traitement de son contenu.

Quelques traitements :

Quelques traitements bash incompatibles avec dash :

Substitution de commande

Cela permet d'affecter le résultat envoyé sur la sortie standard d'une commande à une variable

VARIABLE=$( commande )

ou

VARIABLE=` commande `

Opérations arithmétiques

Il est possible d'effecteur des opérations arithmétiques sur les variables d'environnement et d'affecter le résultat à la même ou bien à une autre variable.

RESULTAT=$(( opération arithmétique ))

L'opération est effectuée et le résultat est affecté à la variable RESULTAT. Les opérateurs sont +,-,*,/ pour la division entière, % pour le modulo. Il est également possible d'utiliser des parenthèses pour grouper des calculs.

Exemple, incrémenter le contenu d'une variable COMPTEUR

COMPTEUR=$(( COMPTEUR + 1 ))

Entrée et sortie

Ecriture de messages sur la sortie standard : l'écran

Par défaut l'écran est la sortie standard. La commande echo suivi du texte entre guillemets affiche ce texte sur l'écran suivi du passage en début de ligne suivante. L'option -n permet d'éviter le passage en début de ligne suivante, le message suivant sera affichés sur la même ligne.

Avec bash, il existe une autre option -e qui permet d'insérer des caractères à partir du code ascii en hexadécimal.
Exemple avec la syntaxe suivante :

echo -e "\x21 bonjour"
qui affiche
!bonjour
En réalité on ne peut pas afficher de message commençant par ! avec bash car le point d'exclamation est une commande. On remplace donc le point d'exclamation par son code ASCII en hexadécimal.

Avec dash, l'option -e n'existe pas et le point d'exclamation est accepté en début de message.

Un autre exemple est l'affichage du caractère antislash "\", qui est utilisé pour afficher des caractères spéciaux comme "\t" pour la tabulation, "\n" pour le saut de ligne. Avec bash : l'option -e fait que ce caractère est interprété avec le caractère qui suit, sans l'option -e le caractère antislash est affiché comme tout autre caractère.
Avec dash, il est interprété avec le caractère qui suit, donc pour afficher le caractère antislash, il faut le doubler ou le tripler si le caractère qui suit peut être interprété comme un caractère spécial.

Les principaux caractères spéciaux sont :

Avec dash pour afficher un message qui contient "\b" il faut écrire "\\\b"

Dans un fichier de script, pour écrire plusieurs lignes, il est possible d'utiliser une commande echo par ligne ou encore insérer des "\n" dans le texte. Il existe une autre solution avec la commande cat comme par exemple :

MESSAGE="ceci est le message"
cat << EOF
bonjour
voici le message
${MESSAGE}
merci
EOF

Cela affiche à l'écran :

bonjour
voici le message
ceci est le message
merci

Le symbole EOF peut être n'importe quelle suite de caractères sans caractères spéciaux

Saisie de messages à partir de l'entrée standard : le clavier

Par défaut le clavier est l'entrée standard. la saisie de donnée depuis le clavier se fait avec la commande read suivi du nom des variables sans le symbole $. Dans le cas où il y a plusieurs variables, il faut effectuer la saisie des valeurs séparées par un espace.

Exemple

echo "valeur ?"
read VALEUR
echo ${VALEUR}

Ces lignes affichent le message "valeur ?" à l'écran, attend la saisie de caractères au clavier, puis affiche la valeur saisie au clavier.

Redirections des sorties

Redirection de la sortie standard vers une fichier

Il est possible d'enregistrer les résultats d'affichages des commandes dans un fichier au lieu de les afficher sur l'écran. Il suffit, pour cela, de rediriger la sortie standard vers un fichier. La sortie standard est identifiée avec le numéro 1, qu'il n'est pas obligatoire de préciser. On utilise pour cela le symbole > pour créer le fichier ou bien l'écraser s'il existe; et le symbole >> pour ajouter le message en fin du fichier existant, dans ce cas, il est créé s'il n'existe pas.

commande > fichier

L'affichage écran de la commande est écrit dans le fichier, si celui-ci existe il est écrasé.

commande >> fichier

L'affichage écran de la commande est ajouté en fin de fichier, si celui-ci n'existe pas, il est créé.

Redirection de la sortie d'erreur vers une fichier

La sortie d'erreur qui, par défaut est l'écran, est identifié avec le numéro 2.. On utilise les mêmes symboles que ceux utilisés avec la sortie standard mais précédés du chiffre 2.

commande 2> fichier

l'affichage des messages d'erreur de la commande est écrit dans le fichier qui est écrasé s'il existe déjà.

commande 2>> fichier

l'affichage des messages d'erreur de la commande est ajouté à la fin du fichier qui est créé s'il n'existe pas déjà.

Il est possible d'utiliser cette redirection pour créer un fichier avec les commandes echo et cat

echo "ligne1 " > fichier.txt
echo "ligne2 " >> fichier.txt
echo "ligne3 " >> fichier.txt
echo "ligne4 " >> fichier.txt
		

ou

cat > fichier.txt << EOF
ligne1
ligne2
ligne3
EOF
		

Redirection des sorties standard et d'erreur

Il est possible de rediriger à la fois les sorties standards et d'erreur vers le même fichier en utilisant les symboles "& >", ou encore en redirigeant la sortie standard vers un fichier, puis la sortie d'erreur vers la sortie standard. Pour cette dernière redirection on utilise les symboles "2> &1".

commande &> fichier
commande > fichier 2>&1 

De la même façon, on peut supprimer l'affichage sur la sortie standard et/ou sur la sortie d'erreur en redirigeant les sorties vers le descripteur /dev/null. Ceci peut être utile pour ne pas avoir d'affichages non désirés pendant le déroulement d'un script.

commande > /dev/null

Ceci supprime l'affichage écran de la commande

commande 2> /dev/null

Ceci supprime l'affichage écran des messages d'erreur de la commande

commande &> /dev/null
commande > /dev/null 2>&1 

Ceci supprime l'affichage écran y compris les messages d'erreur de la commande

Redirection de l'entrée

Cette redirection permet de lire le contenu d'un fichier

read LIGNE < fichier

cela permet de lire une ligne du fichier et de transférer le contenu de cette ligne dans la variable LIGNE. Chaque lecture fait avancer d'une ligne, ce qui permet de lire tout le fichier

Les tubes anonymes

un tube anonyme permet de connecter la sortie standard d'une commande à l'entrée standard d'une autre commande.

commande1 | commande2

La sortie standard de commande1 devient l'entrée standard de la commande2.

Les paramètres de la ligne de commande

Ces paramètres sont les valeurs, séparées par un espace qui suivent le nom de la commande

commande valeur1 valeur2 valeur3 "valeur 4"

Dans le fichier de script, on retrouve ces valeurs dans des variables du type $n avec n numéro d'ordre d'apparition sur la ligne de commande

Dans un script, la commande shift permet de décaler les paramètres : $1 prend la valeur de $2, $2 prend la valeur de $3, ...

La valeur de retour d'une commande

Chaque commande fournit une valeur de retour qui, en général, permet de définir si la commande s'est bien déroulée, qui vaut 0 si tout s'est bien passé et une valeur différente de 0 en cas d'erreur. Cette valeur se trouve dans la variable $?, son contenu peut être utilisée dans le script pour traiter les erreurs.

Les tests

Les opérateurs de comparaisons

Les opérateurs de comparaison arithmétique

  • -eq : test égalité
  • -ne : test inégalité
  • -lt : test inférieur
  • -le : test inférieur ou égal
  • -gt : test supérieur
  • -ge : test supérieur ou égal

Les opérateurs de comparaison de chaînes de caractères

  • -n : chaîne comprend au moins un caractère
  • -z : chaîne vide (aucun caractère)
  • = : égalité lexicographique (= pour dash, avec bash il faut utiliser ==)
  • != : différente lexicographique
  • < : chaîne inférieure au sens lexicographique
  • > : chaîne supérieure au sens lexicographique

Les tests sur les fichiers

Les expressions logiques

Les expressions logiques, que ce soient les comparaisons, les tests de fichiers, sont écrites entre un crochet ouvrant et un crochet fermant séparés par un espace.

[ -f fichier ]

est VRAI si le fichier existe

[ -n "${NOM}" ]

est vrai si la variable NOM contient au moins un caractère

Les opérateurs logiques

Un opérateur logique permet de combiner deux opérations logiques pour fournir un résultat logique en fonction des résultats logiques de chaque opération logique, ou encore de modifier le résultat d'une opération logique.

Exemple

MONSITE="www.perga.fr"
[ -n "${MONSITE} ] && echo "la variable MONSITE existe et contient ${MONSITE}"

affiche

la variable MONSITE existe et contient www.perga.fr

La variable MONSITE contient une chaîne de caractères, le test [ -n "${MONSITE}" ] est VRAI, la commande echo est donc exécutée.

Les structures de contrôle

L'alternative

Elle permet d'exécuter des commandes en fonction du résultat d'un test, la syntaxe est :

if [ expression de test ]
 then
 # commandes si l'expression de test est vraie
 else
 # commandes si l'expression de test est fausse
fi				
				

L'expression de test avec les crochets peut être une opération logique entre plusieurs expressions de test entre crochets

case variable in
 valeur1 )
			# commandes si variable vaut valeur 1
			;;
 valeur2 )
			# commandes si variable vaut valeur 1
			;;
 * )		
			# commandes pour les autres valeurs
			;;
esac			
				

La répétition

C'est une boucle qui effectue une répétition à partir d'une suite de valeurs appartenant à une liste de valeurs (valeurs séparées par un espace)

for variable in liste
do
# commandes à répéter
done
		

Exemple

LISTE=$(seq 1 10)
for compteur in $LISTE
do
echo "$compteur"
done		
		

affiche les chiffres de 1 à 10

La commande seq fournit la suite des nombres de 1 à 10 séparés par un espace.

Les boucles conditionnelles

while [ expression de test ] 
do
# commandes à répéter
done
		

Les commandes sont répétées tant que l'expression de test est VRAIE

until [ expression de test ] 
do
# commandes à répéter
done
		

Les commandes sont répétées jusqu'à ce que l'expression de test soit VRAIE

Exemple d'utilisation pour lire un fichier texte ligne par ligne

while read LIGNE
do
# traitement de la ligne
done < $nomfichier
		

Les fonctions

Il est possible de grouper une suite de commandes au sein d'une fonction afin de pouvoir réutiliser ces mêmes commandes avec des valeurs différentes

Une fonction se déclare avec la syntaxe

nomfonction() {
			
	return valeur
}

Avec ou sans paramètres les parenthèses sont toujours vides. La valeur de retour de la fonction n'est pas obligatoire, cela dépend du rôle de cette fonction.

Les paramètres transmis utilisent le même modèle que les paramètres de la ligne de commande :

La commande shift décale aussi les paramètres

L'appel de la fonction dans le script se fait simplement en utilisant le nom de la fonction comme une commande avec ses propres paramètres.

Après l'appel de la fonction, il est possible d'utiliser la variable $? qui contient la valeur fournie par la commande return dans la fonction.

Les commandes tr et cut

La commande tr

La commande tr est une commande qui remplace un ensemble de caractères par le caractère correspondant dans un deuxième ensemble. Les données sont transmises par l'entrée standard, le résultat est fourni sur la sortie standard. IL existe des options pour modifier le comportement de base de cette commande. En dehors du lien internet fourni, on peut obtenir l'aide sur l'utilisation de cette commande, comme la plupart des commandes linux soit avec l'option "-h" ou "--help" en écrivant :

tr -h

ou encore avec la commande man en écrivant :

man tr

Exemples :

La commande suivante permet de transformer chaque minuscule du texte reçu sur l'entrée standard en majuscule et affiche le résultat de la conversion sur la sortie standard.

echo "perga" | tr "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

qui affiche

PERGA

C'est la position du caractère dans chaque ensemble qui détermine la transformation, il faut donc respecter l'ordre des caractères dans chaque ensemble.

Exemple, changement du séparateur dans un fichier CSV

Soit le fichier "matrice3x3.csv" qui représente une matrice 3x3

1,3,4
5,2,3
9,8,7
				

La commande suivante va modifier le séparateur virgule en point-virgule

cat matrice3x3.csv | tr "," ";"

La commande cat permet d'afficher le contenu d'un fichier sur la sortie standard

Le résultat est affiché à l'écran :

1;3;4
5;2;3
9;8;7				
				

La commande cut

La commande cut permet d'extraire une ou plusieurs colonnes dans un fichier qui contient des chaînes de caractères séparées par un caractère spécial nommé séparateur. C'est le principe des fichiers csv, ce qui fait que cette commande est parfaitement adaptée pour l'extraction de colonnes dans ce type de fichier.

On peut voir un premier exemple d'utilisation en début de cette page. La première ligne avec le fichier password, elle extrait la colonne 7 qui est le nom du shell utilisé. La deuxième ligne elle extrait la colonne 11 de l'affichage ls, qui correspond au nom du fichier correspondant au lien.

Les principales options sont :

Si aucun nom de fichier n'est transmis en paramètre de ligne de commande, c'est l'entrée standard qui est utilisée.

Voir un exemple de calcul de la transposée d'une matrice

Calcul de la transposée d'une matrice enregistrée dans le fichier csv "matrice3x3.csv"

#!/bin/sh
if [ -z "$1" ]
then
	echo "syntaxe $0 nomfichiercsv"
	exit 1
fi
if [ ! -f "$1" ]
then
	echo "$1 n'a pas été trouvé"
	exit 1
fi
FICHIER="$1"
NUMCOLONNE=1
colonne=$( cut -d ',' -f $NUMCOLONNE $FICHIER )
longueur=${#colonne}
while [ $longueur -gt 0 ]
do
	lignebrute=$(echo "$colonne" | tr "\012" ",")
	ligne=$( expr "$lignebrute" : "\(.*\),$")
	echo $ligne
	NUMCOLONNE=$(( $NUMCOLONNE + 1))
	colonne=$( cut -d ',' -f $NUMCOLONNE $FICHIER )
	longueur=${#colonne}
done
					

Le premier test permet de vérifier que le nom du fichier est bien présent sur la ligne de commande. Le deuxième test vérifie que le fichier existe. Ces deux tests terminent le programme avec la valeur de retour 1 s'il manque le nom du fichier ou bien si celui-ci n'existe pas.

Pour la suite il s'agit d'une boucle qui extrait chaque colonne du fichier tant que celle-ci contient des caractères (longueur >0).

cut extrait une colonne de numero NUMCOLONNE en utilisant le séparateur virgule.

Le calcul du nombre de caractères dans la chaîne extraite utilise le symbole # dans la variable colonne.

Dans la colonne extraite le séparateur est un saut de ligne de code 10 en base 10, 0x0A en hexadécimal, et donc 012 en octal. On utilise tr pour transformer les sauts de lignes en virgule de façon à créer une ligne.

Ensuite on utlise expr et une expression régulière pour supprimer la dernière virgule de la ligne. Les paragraphes suivants expliciteront le fonctionnement des expressions régulières et de la commande expr.

A la fin du script, la commande "exit 0" n'est pas obligatoire, car elle est implicite.

Le fichier "matrice3x3.csv" représente une matrice 3x3

1,3,4
5,2,3
9,8,7
					

Le résultat du script est affiché à l'écran :

1,5,9
3,2,8
4,3,7				
					

Les expressions régulières

Une expression régulière est une suite de symboles qui définissent une règle de description d'un ensemble de mots, chaînes de caractères. Cette règle peut être utiliser pour vérifier la présence de mots dans une chaîne de caractères. Lorsque la présence est validée, il est alors possible de supprimer la séquence ou encore de la remplacer par une autre.

Les caractères spéciaux qui définissent les règles sont :

Caractères spéciaux définis par la norme POSIX

POSIXExpression régulière
[:alpha:]a-zA-Z
[:lower:]a-z
[:upper:]A-Z
[:digit:]0-9
[:alnum:]a-zA-Z0-9
[:blank:]espace ou tabulation
[:xdigit:]a-fA-F0-9

La commande expr

La commande expr permet d'effectuer des opérations arithmétiques, des traitements de chaînes de caractères.

Parmi les opérations possibles, on peut citer :

Ici, on va s'intéresser au traitement d'une chaîne avec une expression régulière au travers de quelques exemples :

Une chaîne qui commence par bonjour et se termine par merci

expr "bonjour et merci" : "^bonjour.*merci$"

affiche

16
expr "bonjour et au revoir" : "^bonjour.*merci$"

affiche

0

Une chaîne qui contient une date au format JJ/MM/AAAA

expr "2/3/2023" : "[0-9]\{2\}/[0-9]\{2\}/[0-9]\{4\}"

affiche

0
expr "02/03/2023" : "[0-9]\{2\}/[0-9]\{2\}/[0-9]\{4\}"

affiche

10

Les symboles "\{4\}" ou "\{2\}" représentent la syntaxe exprimant le nombre de répétitions, la présence "\" permet de ne pas confondre le contrôle "{" avec le caractère "{"

Extraire le pays du nom de domaine

expr "www.perga.fr" : ".*\.\([a-z]\{2\}\)$"

affiche

fr
expr "www.perga.us" : ".*\.\([a-z]\{2\}\)$"

affiche

us

Extraire le mois d'une date au format JJ/MM/AAAA

expr "02/03/2023" : "[0-9]\{2\}/\([0-9]\{1,2\}\)/[0-9]\{4\}"

affiche

03
expr "02/3/2023" : "[0-9]\{2\}/\([0-9]\{1,2\}\)/[0-9]\{4\}"

affiche

3

Comme pour les accolades, les parenthèses de mémorisation sont précédées du symbole "\". Pour le mois on accepte 1 ou 2 caractères.

La commande grep

La commande grep permet de trouver les lignes qui contiennent une chaîne de caractères respectant une expression régulière.

grep options regle fichier
Voir un exemple d'extraction des coefficients d'un polynôme dans un fichier gnuplot

On propose d'extraire les coefficients d'un fichier gnuplot afin de créer une variable octave ou scilab.

Fichier courbedegre3.plt

reset

a=-1
b=-6
c=-8
d=-1
f(x)=a*x**3 + b*x**2 + c*x + d

xmin=-7
xmax=3
set terminal X11 0
#set terminal png 
#set output "fonctiondegre3.png"
set title "Fonction degre 3"
set xlabel "x"
set ylabel "f(x)"
set grid
set xr [xmin:xmax]
plot f(x) lw 2 lc "blue"

pause -1

fichier extrairecoefficients.sh

#!/bin/sh

if [ -z "$1" ]
then
	echo "syntaxe $0 nomfichierplt"
	exit 1
fi
if [ ! -f "$1" ]
then
	echo "$1 n'a pas été trouvé"
	exit 1
fi
FICHIER="$1"
COEFFS=$(grep -i "^[a-z]=\-*[0-9\.]\+" $FICHIER)
VECTEUR="["
for coefficient in $COEFFS
do
	SYMBOLE=${coefficient%=*}
	VALEUR=${coefficient#*=}
	VECTEUR="${VECTEUR} ${VALEUR}"  
done
VECTEUR="${VECTEUR} ]"
echo ${VECTEUR}

grep permet d'extraire les lignes qui commence par une lettre minuscule suivi du symbole =, puis d'au moins un chiffre. Le point permet d'accepter les nombres décimaux.

Pour l'exemple présenté, la variable COEFFS contient la chaîne "a=-1 b=-6 c=-8 d=-1"

Cette variable est une liste de valeurs de la forme "a=-1", La boucle for extrait chaque valeur de cette liste dans la variable coefficient.

On utilise les syntaxes des variables d'environnement pour extraire le symbole (a,b,c,...) d'une part et la valeur du coefficient d'autre part.

Ensuite on concatène ces valeurs dans la variable VECTEUR, que l'on écrit sur la sortie standard après la boucle.

Pour l'exemple présenté, l'affichage à l'écran est :

[ -1 -6 -8 -1 ]

La commande sed

La commande sed permet de modifier des lignes d'un fichier texte, ou encore en supprimer ou en insérer en respectant une règle.

sed options -e "script" fichier
Voir un exemple de modification des coefficients et du nom du fichier de l'image dans un fichier gnuplot

On propose maintenant de modifier le fichier gnuplot précédent, c'est à dire modifier les valeurs des coefficients ainsi que le nom du fichier

Fichier modifieplot.sh

#!/bin/bash

if [ -z "$3" ]
then
	echo "syntaxe $0 fichier chainecoeffs fichierimage"
	exit 1
fi
FICHIER="$1"
CHAINECOEFFS="$2"
IMAGE="$3"
COEFFS=$(echo "$CHAINECOEFFS" | sed -e 's/,/ /g')
N=0
if [ -f script.txt ]
then
	rm -f script.txt
fi
for coeff in ${COEFFS}
do
	symbole=$( echo -n $N | tr "0123456789" "abcdefghij" )
	echo "s/^\(${symbole}=\)\-*[0-9\.]\+/\\1${coeff}/g" >>  script.txt
	N=$(( N + 1))
done
echo "s/set \+output \+\".\+\"/set output \"${IMAGE}\"/g" >> script.txt
sed -f script.txt ${FICHIER} 
rm -f script.txt
					

La chaîne des coefficients est une suite de nombres décimaux séparés par une virgule (le séparateur décimal est le point).

Comme il y a plusieurs lignes à changer, on va utiliser un fichier de script qui est construit au fur et à mesure du déroulement du script.

Les noms des symboles (a,b,c,...) sont créés à partir du chiffre 1,2,3,... en appliquant la commande tr pour les transformer en lettres minuscules.

Une ligne de script est construite pour chaque coefficient.

Après la boucle, on ajoute la ligne de modification du nom du fichier image au script.

En appliquant la commande

./modifieplot.sh courbedegre3.plt "1,2.5,4,2.3" courbe.png > courbe.plt

on obtient le fichier courbe.plt

reset

a=1
b=2.5
c=4
d=2.3
f(x)=a*x**3 + b*x**2 + c*x + d

xmin=-7
xmax=3
set terminal X11 0
#set terminal png 
#set output "courbe.png"
set title "Fonction degre 3"
set xlabel "x"
set ylabel "f(x)"
set grid
set xr [xmin:xmax]
plot f(x) lw 2 lc "blue"

pause -1
					

La commande awk

commande et fichier de script

La commande awk est un outils de traitement de texte élaboré qui peut appliquer plusieurs règles, extraire des informations, effectuer une conversion de format, effacer des lignes, insérer des lignes, ... .

awk "fichier script" fichier
awk "chaine script" fichier

Le fichier script a le format suivant :

#!/bin/awk -f

BEGIN {
# pré traitement avant le début du fichier
}

# instructions de traitement des lignes

END { 
# post traitement après la fin du fichier
}
		

Si le fichier script est exécutable, il est directement utilisable comme une commande.

Les variables prédéfinies

awk traite un fichier comme une suite d'enregistrements qui sont, par défaut, des lignes. Chaque ligne est traitée comme une suite de champs séparés par un caractère séparateur.

VariableDescriptionValeur par défaut
FSséparateur de champs en entréeespace
OFSséparateur de champs en sortieespace
RSséparateur d'enregistrements en entrée'\n'
ORSséparateur d'enregistrements en sortie'\n'
FNRnombre d'enregistrements du fichier
NRnombre d'enregistrements déjà lus
NFnombre de champ de l'enregistrement en cours
ARGCnombre d'arguments de la ligne de commande
ARGVtableau des arguments de la ligne de commande

Les variables qui représentent un enregistrement sont

On propose de construire une matrice sous la forme d'un fichier CSV à partir d'une matrice exprimée sous la forme d'une chaîne de caractères. Dans la chaîne les colonnes sont séparées par des virgules et les lignes par des points virgules.

Contenu du fichier de script nommé chaineversmatrice.awk :

#!/bin/awk -f

BEGIN {
	FS=",";
	OFS=",";
	RS=";";
	ORS="\n";
}

{
	print $0;
}

Pour réaliser cette conversion, il suffit de définir les valeurs des séparateurs en entrée et en sortie.

Exécution de la commande

echo "1,2,3;5,4,8;9,0,7" | ./chaineversmatrice.awk

Affiche

1,2,3
5,4,8
9,0,7

Le motif

Le motif contient une expression régulière qui définit l'enregistrement à traiter, comme par exemple

/expression/ {
# traitement de l'enregistrement définie par l'expression régulière
}
$0 ~ /expression/ {
# traitement si $0 contient l'expression régulière
}
$0 !~ /expression/ {
# traitement si $0 ne contient pas l'expression régulière
}
$0 ~ /expression 1/ || $0 ~ /expression 2/{
# traitement si $0 contient l'expression 1 ou bien l'expression 2
}
$0 ~ /expression 1/ && $0 ~ /expression 2/{
# traitement si $0 contient l'expression 1 et l'expression 2
}

Les fonctions et structures de contrôle

Affichage sur la sortie standard

Cela se fait avec print suivi de la liste des valeurs à afficher séparées par des virgules

Il est également possible d'utiliser la sortie formatée printf "format",liste variables

La chaîne format contient du texte ainsi que des caractères de formatage des variables, comme par exemple :

Les structures de contrôles

Il s'agit de l'alternative, et des boucles qui sont de la forme :

if (expression booléenne) {
# traitement si expression booléenne vraie
}
else {
# traitement si expression booléenne fausse
}
			
for(expression1;exprssion2;expression3) {
# traitement itératif
}
			

expression1 initialise la variable de boucle

expression2 est la condition de continuité de la boucle (tant que)

expression3 est le calcul de l'évolution de la boucle

while (expression) {
# traitement tant que expression varie
}
			

Les éléments de l'expression doivent avoir une valeur afin que l'expression soit définie avant l'entrée dans la boucle

Les fonctions

awk possède des fonctions de traitement de données, on citera, ici quelques fonctions de traitements de chaînes de caractères

Les tableaux

Un tableau représente un ensemble de valeurs ou chaque valeur ou élément est accessible avec l'indice de sa position précisée entre crochets.

Cet indice est traité comme une chaîne de caractères, ce qui permet de construire des tableaux à deux dimensions.

Voir un exemple d'utilisation d'un tableau

Exemple qui inverse l'affichage d'un fichier texte en commençant par la dernière

Fichier inversefichier.awk

#!/bin/awk -f

BEGIN {
	n=0;
}

{
	tableau[n] = $0;
	n+=1;
}

END { 
	for(i=n-1;i>=0;i-=1) {
		print tableau[i];
	}
}
					

Le pré-traitement est utilisé pour initialiser la variable d'indice du tableau

Le traitement de chaque ligne stocke la ligne courante dans un élément du tableau, ensuite l'indice est incrémenté de 1

Le post-traitement affiche sur la sortie standard le contenu du tableau élément par élément en commençant par le dernier. Ce qui a pour effet d'afficher le contenu du fichier en commençant par la dernière ligne

La commande pour utiliser ce code est

./inversefichier.awk matrice3x3.csv

avec matrice3x3.csv qui contient

1,3,4
5,2,3
9,8,7

affiche le résultat

9,8,7
5,2,3
1,3,4
Voir un exemple d'utilisation d'un tableau à deux dimensions

Exemple qui calcule la transposée d'une matrice

Fichier transpose.awk

#!/bin/awk -f

BEGIN {
	m=0;
	FS=",";
}

{
	for(i=1;i<=NF;i+=1) {
		indice = sprintf("%s,%s",m,i-1);
		matrice[indice] = $i;
	}
	m+=1;
	n=NF;
}

END { 
	for(i=0;i<m;i+=1) {
		for(j=0;j<n;j+=1) {
			indice = sprintf("%s,%s",j,i);
			printf "%s",matrice[indice];
			if (j < n-1) {
				printf ",";
			}
		}
		printf "\n";
	}
}

					

Le pré-traitement initialise l'indice à 0 et initialise le séparateur du fichier csv avec le symbole virgule.

Le traitement de chaque ligne enregistre les valeurs de chaque champ dans une rangée du tableau à deux dimensions. L'indice du tableau est une chaîne qui est construite à partir de l'indice de ligne m et de l'indice de colonne i.

Le post-traitement affiche la matrice colonne par colonne, ce qui a pour effet d'afficher la transposée de la matrice.

La commande pour utiliser ce code est

./transpose.awk matrice3x3.csv

avec matrice3x3.csv qui contient

1,3,4
5,2,3
9,8,7

affiche le résultat

1,5,9
3,2,8
4,3,7