Fonction assert

Présentation

Si vous programmez dans des langages plus évolués, la fonction assert ne vous est probablement pas inconnue.

Je vous propose donc une version pour Bash qui présentent quelques astuces dans sa mise en œuvre.

Utilisation

La fonction s'appelle de la façon suivante :

assert "Message d'erreur" assertion

Le premier paramètre est une chaîne de caractères qui sera affichée si jamais l'assertion n'était pas vérifiée.

Les paramètres suivants sont compris comme une commande complète à exécuter. Si cette commande retourne un code de retour différent de zéro, la fonction stoppe l'exécution du script en cours, affiche le message d'erreur et retourne le code de retour de l'assertion.

Notes

Utilisation de "$@"

On connaît souvent le paramètre spécial $* mais on en oublie tout aussi souvent le paramètre spécial $@. Ces deux paramètres sont très proches l'un de l'autre mais seul le paramètre $@ est intéressant pour la fonction assert.

Quand un script est appelé de la façon suivante :

script "Param 1" "Param 2"

$1 reçoit "Param 1" et $2 reçoit "Param 2"

Si le script utilise $* dans une commande, la commande recevra à son tour "Param" "1" "Param" "2".

Si le script utilise "$@", la commande recevra à son tour "Param 1" "Param 2", les paramètres seront donc ainsi bien conservés.

Cette particularité est cruciale pour la fonction assert en Bash si on veut passer une commande sans devoir la protéger avec des double quotes ce qui alourdirait son utilisation.

Utilisation de caller

La commande caller de Bash permet de retourner le numéro de la ligne appelant notre fonction ainsi que le script qui a fait l'appel. C'est très pratique lors de l'affichage du message d'erreur car cela permet d'indiquer la ligne qui a généré l'assertion. Du coup le développeur n'a pas besoin d'indiquer $LINENO dans l'appel de la fonction assert pour indiquer le numéro de ligne courante.

Code source

#!/bin/bash

function assert {
  # First parameter is the message in case the assertion is not verified
  message="$1"

  # The remaining arguments make the command to execute
  shift

  # Run the command, $@ ensures arguments will remain in the same position.
  # "$@" is equivalent to "$1" "$2" "$3" etc.
  "$@"

  # Get the return code
  rc=$?

  # If everything is okay, there's nothing left to do
  [ $rc -eq 0 ] && return 0

  # An error occured, retrieved the line and the name of the script where
  # it happend
  set $(caller)

  # Get the date and time at which the assertion occured
  date=$(date "+%Y-%m-%d %T%z")

  # Output an error message on the standard error
  # Format: date script [pid]: message (linenumber, return code)
  echo "$date $2 [$$]: $message (line=$1, rc=$rc)" >&2

  # Exit with the return code of the assertion test
  exit $rc
}

Exemple d'utilisation

#!/bin/bash

function assert { ... }

directory="$1"

assert "There must be one argument" test $# -eq 1
assert "Directory $directory does not exist" test -d "$directory"
assert "Directory $directory is not readable" test -r "$directory"
assert "Directory $directory is not writable" test -w "$directory"
assert "Directory $directory is not executable" test -x "$directory"