La Commande expr

Bon, je vais essayer de ne pas traduire le man de expr qui se trouve être sous mes yeux... Cependant, je vais essayer de clarifier certains points et donner quelques autres exemples d'utilisation.

Description
Justement, comme le dit si bien le man, expr est un utilitaire qui évalue des expressions (ses arguments) et envoie ses résultats sur la sortie standard.

Les arguments
Les expressions manipulées par expr pouvant être composées, expr en devient très puissant.

Les opérateurs

Tout d'abord, une expression peut être le résultat d'une opération, voici par ordre de priorité croissante les divers opérateurs qu'accepte expr.
expr ::= expr \| expr Retourne le premier opérande si celui-ci n'est ni NULL ni égal à 0, sinon retourne le second.
expr ::= expr \& expr Retourne le premier opérande si aucun n'est NULL ni égal à 0, sinon retourne 0.
expr ::= expr { =, \>, \>=, \<, \<=, != } expr Retourne un booléen dans le cas de comparaison entière, sinon retourne le résultat d'une comparaison lexicale.
expr ::= expr { +, - } expr Addition ou soustraction entière.
expr ::= expr { \*, /, % } expr Multiplication, division ou modulo sur des opérandes entiers.
expr ::= expr : expr : est l'opérateur que je qualifierai de correspondance (matching operator). Il effectue une comparaison entre les deux opérandes, le dernier étant considéré comme une expression régulière.
Cet opérateur retourne le nombre de caractères communs entre les deux opérandes. Cependant, il fonctionne en tout ou rien : si l'expression régulière ne colle pas parfaitement au premier opérande, 0 sera retourné.
Enfin, il est possible d'extraire une sous-chaîne commune avec le premier opérande plutot que le nombre de caractères communs. Cela se réalise avec les paranthèses ; cf. le paragraphe suivant.

J'avoue j'ai grandement repiqué la table au man, mais je le trouvais peu clair concernant le matching operator.

Les parenthèses

Les parenthèses peuvent être utilisées de deux façons :
  • Pour combiner des expressions et modifier les priorités : cela correspond aux parenthèses classiques des maths : on groupe des calculs.
    ex. :
    $ expr \( 1 + 2 \) \* \( 3 + 4 \) Calcule (1+2).(3+4) et renvoie donc 21
    $ expr \( $a \| dRIENd \) : 'd\(.*\)d' Si $a est de la forme 'd.*d', on renvoie la sous-chaîne de $a entre les deux 'd', sinon on renvoie 'RIEN'.
    Le premier couple de parenthèses sert ici à vérifier si $a est NULL ou non et si c'est le cas, on renvoie le second argument de \|. Ensuite, on extrait une sous-chaine entre deux 'd'.
    Sans ces premières parenthèses, on aurait renvoyé $a s´il avait été non-NULL ou sinon 'RIEN'.
    Bien sûr, une autre façon de procéder aurait été de faire :
    $ expr $a : 'd\(.*\)d' \| RIEN

  • Les parenthèses s'utilisent également pour extraire des sous-chaînes d'une chaîne de caractères. Ce cas s'utilise avec l'opérateur de matching et dans une expression régulière. Cela correspond à la seconde utilisation des parenthèses dans l'exemple précédent. Cependant, quelques précautions sont à prendre :
    $ expr dhd : 'd\(.*\)d' Cas d'utilisation normale : on extrait la sous-chaîne composée de caractères quelconques comprise entre deux 'd'.
    $ expr $a : 'd\(h\)d' ou
    $ expr $a : d\(h\)d
    On extrait la sous-chaîne 'h', si $a est 'dhd'.
    On remarquera que sans caractères significatifs pour le shell, on n'est pas obligé de mettre des apostrophes (ou des guillements) En revanche, il est impératif en l'abscence de guillemets de banaliser les parenthèses.
    $ expr $a : 'd(h)d' On cherche la sous-chaîne 'd(h)d', les '(', ')' étant comprises comme des caractères à part entière. Ainsi, on retournera 5 si et seulement si $a vaut 'd(h)d'.

    Ainsi, il faut retenir que pour pouvoir accéder à une sous-chaîne, il convient d'utiliser l'opérateur de matching, et que l'expression régulière doit contenir '\(' et '\)'.
    Il est à noter que l'utilisation des parenthèses modifie le type de résultat renvoyé par l'opérateur de matching : on renvoie en effet une sous-chaîne et non plus le nombre de caractères en commun.

Les éléments(ou unités ?) léxicaux

Les éléments terminaux sont de deux types : les entiers et les chaînes de caractères.

expr ::= entier Entiers signés
expr ::= chaîne Chaînes de caractères

Il est à noter que par défaut expr essaie d'interpréter les arguments comme des entiers.

Exemples
Enfin, pour vérifier dans un test le nombre de caractères communs :
    [ `expr $1 : '[+-].*'` -gt 0 ] 
D'autres exemples....
    expr //$a : '*/\(.*\)\.[^\.]*$'


Derniers conseils
  • N'oubliez pas de séparer vos arguments par des espaces... en effet, chaque terme se doit d'être un paramètre de l'exécutable expr.
  • Il ne faut pas oublier de banaliser les caractères qui ont du sens pour le shell, c'est à dire : |, &, <, >, *, (, )
  • Pour définir vos expressions régulières, pensez à mettre des apostrophes (quotes) -- en effet, la répétition et autres caractères ont un sens prédéfini pour le shell.