Utiliser le bash

Enfin voici ce qui fait tant peur aux non geek : la ligne de commande et le bash. Nous allons présenter quelques trucs utile à connaître sur ce fameux bash.

C'est quoi le bash ?

Le bash ne s'utilise qu'à travers un terminal. Cela n'a rien de graphique même si on peut lancer un scripts bash à partir d'un programme graphique comme "Nautilus" ou "Dolphin" par double clic.

On va définir le bash comme le programme qui va traiter la commande saisie sur un terminal et passer ainsi des commandes aux système d'exploitation et vous afficher les différents messages et résultats.

La doc ultime sur le bash est ici.

L'historique des commandes

Quand vous saisissez une commande sur la console, le bash va mémoriser dans un fichier caché de votre répertoire personnel (.bash_history) la commande exécutée.

Il est possible de ré afficher les commandes passées pour les réutiliser. Utilisez pour cela les flèches de direction vers le haut ou le bas (pour revenir en arrière dans la navigation).

Les raccourcis clavier

Une fois affichée il est naturellement possible de modifier cette commande. Vous pouvez utiliser les flèches vers la gauche ou vers la droite pour vous déplacez sur la ligne mais il existe des raccourcis.

Raccourcis bash
Raccourcis Commande
[Ctrl] + a Home
[Ctrl] +e Fin
[Alt] + f Avance d'un mot
[Alt] + b Recule d'un mot
[Ctrl] +d Supprime un caractère
[Ctrl] +K Supprimer tout ce qui est à droite du curseur
[Ctrl] + u Supprimer tout ce qui est à gauche du curseur
[Ctrl] + w Supprime le mot à gauche
[Ctrl] +l Effacer l'écran
[Ctrl] +r Permet de réaliser une recherche dans votre historique (super pratique)
[Ctrl] +d Quiter le bash
[Ctrl] +p Rappeler la commande précédente

La complétion

Le bash serait invivable s'il fallait tout saisir. Heureusement les gars ont inventé la complétion. Le principe est simple : vous saisissez le début puis vous appuyez sur la touche [Tab] et le bash complète (s'il le peut) la commande ou le nom du fichier ou du dossier que vous êtes en train de saisir.

Avec un exemple cela ira mieux. On suppose que dans votre dossier personnel vous avez un fichier dénommé "testscript.sh". Si vous souhaitez en afficher les caractèristiques vous allez faire un "ls -la" suivi du nom du fichier. Vous tappez donc "ls -la t" puis vous appuyez sur [Tab]. Si vous n'avez qu'un seul fichier ou répertore commençant par un "t" alors le bash va saisir pour vous "estscript.sh".

Les variables d'environnement

Un truc fondammental en bash : les variables d'environnement. Ce n'est pas un notion aisée à comprendre. Sachez que ce sont des mots qui désignent quelque chose. Il y a un mot qui dit comment le prompt doit se présenter. Il y a un mot qui permet d'indiquer les répertoires où le système chechera les programmes que vous voulez exécuter.

Le premier mot est PS1, le second est PATH.

Vous pouvez les afficher via la commande "echo"

Saisissez la commande suivante :

$ echo $PATH

qui donne chez moi

/home/jfd/JDK/jdk7/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games

Ce sera différent chez vous naturellement.

Si vous voulez connaître les autres variables d'environnement saisissez la commande "env" dans une console.

Les calculs

Bash s'est un peu calculer. La syntaxe à utliser est "$(( ... )). Exemple :

$ echo $((5*6))

qui donne bien "30".

Autre possibilité de faire des calculs : la commande let. Voici un exemple d'utlisation :

$ let x=4*6

Vérifiez le résultat via la commande :

$ echo $x

La manipulation des texte

J'ai écrit une page spéciale pour ces fonctions ici.

Les variables

Une variable est un mot qui contient une valeur. L'intérêt de l'utlisation des variables est que cela rend les scripts en bash plus facilement lisible.  Exemple :

$ temperature_du_corps=37

Vous pouvez afficher le contenu de cette varaible par un écho :

$ echo $temperature_du_corps

On peut donc parfaitement écrire les lignes suivantes :

$ un=1

$ deux=2

$ trois=$(($un+$deux)

$ echo $trois

Je vous laisse deviner le résultat.

Les scripts

On passe souvent des ordres au bash dans un terminal mais son intérêt est de pouvoir automatiser des commandes en les enregsitrant dans un fichier afin de pouvoir les rejouer à sa convenance ou en les faisant lancer par un automate (cron).

Les scripts doivent commencer par dire quel programme va l'exécuter. Il peut paraitre aller de soit que cela sera bien le bash. Mais cela pourrait être un autre interpréteur de commande (ksh, csh, etc) ou un autre langage (perl, python, php,etc..).

Pour dire qui va faire on ajoute la ligne suivante en tout début de fichier :

#! /bin/bash

On appelle cette ligne le shebang.

Et dans un bon script on trouve de nombreux commentaires. Pour ajouter des commentaires on les débute par un "#". Ainsi :

# Ceci est un commentaire

sera ignoré par le bash lors de l'exécution du script.

Les scripts renverront à l'issue de leur exécution un code retour qui pourra êtrelu via la variable "$?".

Les paramètres

Vos scripts peuvent recevoir des paramètres. Cela permet à votre script d'être plus modulable. Les paramètres sont saisis à la suite du nom du script qui est lancé. L'ordre peut avoir son importance. Exemple de paramètres :

$ ./mon_script.sh param1 param2

Dans mon script je peux ajouter les commandes suivantes pour vérifier le passage des paramètres. Le début de mon script ressemble donc à cela :

#!/bin/bash

echo $0

echo $1

echo $2

qui donne :

Au dela de 10 paramètres vous devez mettre "${10}, etc...

Pour connaître le nombre de paramètres transmis utlisez la variable "$#". Cela vous permettra de vérifier si le nombre de paramètres passés est correct.

Il existe une varaibe spéciale qui vous retourne tous les paramètres sous forme de liste.

En ajoutant les lignes suivantes au script présenté ci dessus :

echo $#
echo $@

vous obtenez :

Une fois récupéré vous pouvez supprimer un paramètre avec l'instruction "shift". Exemple avec notre script :

#!/bin/bash
echo $@
echo $1
echo $#
shift
echo $1
echo $#

On pourrait penser que l'on affiche toujours le même paramètre mais comme on le supprime le second devient le premier. Ce qui donne :

Vous pouvez poursuvre cette découverte avec les test en bash ici.

Vous pouvez obtenir le même type de résultat avec ce type fonction :

while [ $# -ne 0 ]; do
  echo $1
  shift
done

ou $# vous donne en nombre de paramètres (restant).

If then else :

Vous aurez souvent dans vos scripts des tests à réaliser en fonction du résultat vous ferez quelque chose ou autre chose. C'estce à quoi sert le "if". Exemple : si un fichier existe je le dis sinon je dis qu'il n'existe pas :

if [ -f /etc/hosts ]

then

echo "Le fichier existe"

else

echo "Le fichier n'existe pas

fi

A noter que vous pouvez l'écrire aussi comme cela :

if [ -f /etc/hosts ]; then
echo "Le fichier existe"
else
echo "Le fichier n'existe pas"
fi

Quand le "then" est sur la même ligne il faut le  séparer par un ";".

Entre les lignes then et fi ou else et fi vous pouvez mettre autant de commande que vous souhaitez.

Si vous voulez mettre un "sinon si" vous devez utliser "elif". Exemple :

#!/bin/bash
a=3
b=6
if [[ a -gt b ]]; then
  echo "a est plus grand que b"
elif [[ a -lt b ]]
then
  echo "a est inféeriur à b"
else
  echo "a est égal à b"
fi

Le case : le choix multiple

#!/bin/bash
read -p "Continuer (Oui/Non) " une_reponse
case $une_reponse in
      'o'|'O')
          echo "On continue"
          ;;
      'n'|'N')
          echo "On arrete"
          ;;
      *)
          echo "Reponse incorrecte"
          ;;
esac

N'oubliez pas les deux points virgules aprés le bloc qui traite un cas. Les autres cas possibles sont traités dans le bloc étoile.

Les listes :

Les listes sont contituées par des parenthèses. Exemple :

mois=('Janvier'  'Février'  'Mars'  'Avril' 'Mai' 'Juin'  'Juillet'  'Aout'  'Septembre'  'Octobre'  'Novembre'  'Decembre');

echo $mois

echo ${mois[2]}

Le premier echo affiche le premier mois. Pour afficher les suivant il faut ajouter la strucyure ${} plus l'indice de l'élément recherché.

Pour modifier un élément vous pouvez faiire comme suit :

$ mois[11]=Décembre

On ne met pas de signe dollar.

Pour vériifer on va afficher toute la liste comme suit :

$ echo ${liste[*]}

ou

$ echo ${mois[@]}

Et un dernier truc de faignant : vous p ouvez directement déclarer une liste comme suit :

$ tab[0]=Janvier

La boucle for

Cette boucle permet des itérations dont on connait le nombre.

La syntaxe de la boucle for est la suivante :

 #!/bin/bash
mois=('Janvier'  'Février'  'Mars'  'Avril' 'Mai' 'Juin'  'Juillet'  'Aout'  'Septembre'  'Octobre'  'Novembre'  'Decembre');
i=0
for m in ${mois[*]}
do
  i=$((i+1))
  printf "Le mois no %2s est : %-15s\n" $i $m
done

Notez l'utilisation de la commande "printf" qui permet d'afficher du texte en le formatant. Printf ne fait pas de retour à la ligne contrairement à "echo". Avec printf vous pouvez cadrer à droite "%15s" ou à gauche "%-15s".

On peut avec cette boucle afficher les arguments reçus :

#!/bin/bash
i=0
for arg in $*
do
  i=$((i+1))
  printf "L'argument no %2s est : %-15s\n" $i $arg
done

Essayez en exécutant le script comme suit :

./test3.sh 1 2 3 4 5 6 4

On peut travailler avec le résultat de commande. Si on veut traiter les fichiers présents dans un dossier on va faire un for de ce type :

for fichier in `ls *`

do

  echo $fichier

done

On peut écrire aussi : "for fichier in *" ou "for fichier in $(ls *)". A noter qu'avec "$( )" vous pouvez faire exécuter n'importe quelle commande disponible sous bash.

Travailler avec les fichiers

Avec un fichier texte qui contient ceci :

Janvier
Février
Mars
Avril
Mai
Juin
Juillet
Aout
Septembre
Octobre
Novembre
Decembre

Le script a cette forme :

#!/bin/bash
i=0
for m in $(cat mois.txt)
do
  i=$((i+1))
  printf "Le mois no %2s est : %-15s\n" $i $m
done

Cela fonctionne bien mais le soucis peut être que tous les mots séparés par un espace seront individualisés. Si vous remplacez la première ligne du fichier par "Le mois de Janvier" le script donnera pour cette seule ligne le résultat suivant :

Le mois no  1 est : le            
Le mois no  2 est : mois          
Le mois no  3 est : de            
Le mois no  4 est : Janvier

Si vous souhaitez traiter les lignes une par une vous devez utliser la commande "while" et le script devient :

IFS=$'\n'
i=0
while read m
do
  i=$((i+1))
  printf "Le mois no %2s est : %-15s\n" $i $m
done < mois.txt

L'IFS permet d'indiquer ce qui sépare les éléments. Si c'est un caractère blanc tous les mots seront séparés les uns des autres mais si 'est un retour chariot toutes les lignes sont considérées comme des éléments.

A noter que cela fonctionne aussi avec la boucle "for".

Les fonctions :

Comme tout langage qui se respecte le bash a des fonctions. On les presente comme suit :

ma_fonction()

{

  return 0

}

On n'est pas sur un langage si évolué que cela : les fonctions n'ont qu'un code retour qui doit être numérique : 0 tout s'est bien passé et 1 à 255 dans le cas  contraire. Atention donc si vous souhaitez renvoyé des résultats qui peuvent être supéreur à 255, vous aurez n'importe quoi.

Exemple avec le fichier des mois précédemment utilisé :

#!/bin/bash
IFS=$'\n'

litMois()
{
while read m
do
  lesmois+="${m}|"
done < mois.txt
echo ${lesmois::-1}
return 0
}
liste=$(litMois)
IFS='|' read -r -a lmois <<< $liste

for (( i=0; i < ${#lmois[*]}; i++ ))
do
  echo ${lmois[i]}
done

La fonction "litMois" va lire le fichier texte des mois en renvoyer une chaine de caractères dont les données sont séparées par un "|".  La ligne "${lesmois::-1}" permet de supprimer le dernier caractère de la ligne.

Ce qui est étonnant est que les echo n'ont ne provoque pas d'affichage. Sans le echo la fonction ne marche pas car l'assignation dans la variable "liste" n'est pas faite.

Ensuite la variable "liste " est découpée suivant le séparateur "|". Les différents valeurs sont copiées dans un tableau "lmois" grace au cimmutateur "-a".

Il ne reste plus qu'à afficher le tableau.

Le passage de paramètres à une fonction :

Tout comme les scripts les fonctions peuvent revevoir des paramètres.

Dans la fonction vous allez manipuler les paramètres avec $1, $1, etc.. ainsi que $@ (liste des paramètres) et $# (nombre de paramètres).

Pour les transférer à la fonction il suffit de la ajouter à la ligne d'appel. Exemple :

mafonction() {

   echo $1

}

 

mafonction "Bonjour"

Pour pouvoir avoir des retours supérieurs à 255 vous pouvez faire comme suit :

max() {

    if [ $1 -gt $1 ]

    then

        echo $1

    else

        echo $1

}

 

REP=$(max $1 $2)

echo $REP

Si à la place d'un "echo" vous aviez utilisez un "return" la fonction aurait retourné des résultats faux avec des des valeurs supérieures à 255.

Expressions rationnelles

Vous pouvez utliser des expressions rationnelles dans vos tests if avec les doubles crochets :

[[   ]]

Exemple si on veut tester les fichiers qui commencent par les lettres "t" ou "u" on peut écrire le test suivant :

for fichier in $(ls *)
do
  if [[ $fichier =~ ^[tu].* ]]
  then
    echo $fichier
  fi
done

Fait le 29/07/2016

Tags: