Bonjour,
Je vais vous parler d'un sujet qui m'intéresse, le shell. A mon avis le shell actuel qu'on a sur nos machines (souvent bash) a deux gros problèmes, et j'aimerais bien ouvrir une discussion là dessus à l'occasion d'un développement récent que j'ai fait.
1. L'expansion des variables
Tout d'abord, le premier problème du shell sh ou compatible est à mon avis, outre sa syntaxe parfois bizarre, le problème de l'expansion des variables. Pour justifier mes griefs sur la syntaxe, je dirais simplement que je ne vois pas pourquoi les routines sont délimitées par des { } et pas les constructions if/for/case, pourquoi le if se termine par fi, le case par esac et le for/while par done et non pas rof/elihw.
penchons-nous sur le problème de l'expansion des variables. Le problème c'est que le shell découpe les mots après l'expansion des variables, c'est à dire que :
var="mot1 mot2"
cmd a b${var}c d
est équivalent à :
cmd a bmot1 mot2c d
et non pas :
cmd a "bmot1 mot2c" d
Alors que dans le code source on ne voit que 3 arguments passés à la commande cmd (a, b${var}c, d), il y en a en fait réellement 4 (a, b$mot1, mot2c, d).
Ce comportement peut être désirable dans certains cas, mais parfois vraiment malvenu. Par exemple lorsqu'on manipule des noms de fichiers contenant des espaces. En gros cela impose lorsqu'on ne sait pas précisément ce qu'il y a dans la variable à toujours l'entourer de quotes, c'est à dire écrire "$var" au lieu de $var.
Non seulement les débutants qui commencent ne comprennent pas toujours cette subtilité et oublient les quotes, mais bien souvent aussi, des gens expérimentés les oublient en les pensant inutiles.
Un exemple concret. la distribution ArchLinux utilise des script bash pour compiler les logiciels et créer des paquets, on les appelle PKGBUILD (un peu similaires aux ebuilds de gentoo). L'exemple le plus courrant et qui sert de modèle à tous les PKGBUILD est¹:
build() {
cd $startdir/src/$pkgname-$pkgver
./configure --prefix=/usr
make || return 1
make prefix=$startdir/pkg/usr install
}
Où $startdir est le dossier dans lequel les sources se trouvent, et où les fichiers sont installés.
Ici on peut voir que $startdir n'est jamais entre quotes, c'est à dire qu'il est impossible de compiler un package si le chemin courrant contient des espaces !!! En effet, la première commande (cd) échoue déjà car au moins deux arguments lui sont passés en paramètres.
C'est ma première critique concernant la robustesse des script shell.
2. La lenteur
Bash, c'est lent. On le voit avec les script d'init, et je l'ai remarqué plus récamment en remplaçant mon script monolithique ~/.xsession par de nombreux scripts modulaires qui me permet à chaque démarrage de:
- me demander mon mot de passe ssh
- lancer quelques programmes comme xbindkeys, mpd
- demander quelle session lancer (E17, GNOME, KDE, Terminal ...)
Et je constate facilement que c'est lent.
Je sais bien que si on veut faire quelque chose de rapide, on utilise plus quelque chose comme python que bash, mais le shell a tout de même l'avantage de pouvoir facilement lancer des applications tierces facilement, éventuellement de manière asynchrone, en modifiant l'environnement, et en redirigeant les entrées/sorties. Si on veut faire la même chose avec un langage classique, je pense que c'est d'un coup moins facile (si on omet la fonction system() qui utilise d'ailleurs le shell).
Sans compter des projets complexe entèrement programmés en bash. Par exemple le gestionnaire de paquets de Nasgaïa est comme ça (ca a peut être changé depuis). Et ne serait-ce qu'afficher l'aide prend un temps fou.
je me demande alors dans quelle mesure (et je vous pose la question) il ne serait pas intéressant d'avoir un interpréteur shell (type sh ou autre) constamment chargé en mémoire qui pourrait rapidement exécuter n'importe quel script. Bien entandu une attention particulière doit être portée à la sécurité.
3. mon code
je vois ai dit que j'avais codé quelque chose, mais quoi ? J'ai commencé un shell basé sur le langage jam². Jam est un remplaçant à make(1) et possède un langage de script qui a les facultés suivantes :
- les variables ne contiennent pas une seule valeur, mais des listes de chaînes de caractères.
- lors de l'expansion des variables est le produit de tous les termes. Pour illustrer cela, je prend juste l'exemple donné dans la documentation³:
$(X) -> a b c
t$(X) -> ta tb tc
$(X).txt -> az bz cz
$(X)-$(X) -> a-a a-b a-c b-a b-b b-c c-a c-b c-c
- la ponctuation n'est pas reconnue si elle n'est pas entourée d'espaces. Cela permet d'avoir de la ponctuation sans problèmes à l'intérieur des mots.
Ce que j'ai fait à partir de ça, c'est relativement simple. J'ai supprimé toute la partie qui s'occupait de la compilation, de la gestion des dépendances entre les cibles, pour ne garder que le langage Jam et faire en sourte que si une fonction n'est pas reconnue de manière interne par Jam, le programme correspondant dans le $PATH soit exécuté. Et cela n'a pris que quelques heures.
Mon code est disponnible sur launchpad⁴ et si cela vous intéresse, plus de détails dans mon e-mais sur la mailing list de jam⁵.
Des remarques ?
¹ http://wiki.archlinux.org/index.php/ABS_-_The_Arch_Build_Sys(...)
² http://freetype.sourceforge.net/jam/index.html
³ http://public.perforce.com/public/jam/src/Jam.html
⁴ https://code.launchpad.net/~mildred/+junk/jam-shell
⁵ http://maillist.perforce.com/pipermail/jamming/2007-November(...)
Je vais vous parler d'un sujet qui m'intéresse, le shell. A mon avis le shell actuel qu'on a sur nos machines (souvent bash) a deux gros problèmes, et j'aimerais bien ouvrir une discussion là dessus à l'occasion d'un développement récent que j'ai fait.
1. L'expansion des variables
Tout d'abord, le premier problème du shell sh ou compatible est à mon avis, outre sa syntaxe parfois bizarre, le problème de l'expansion des variables. Pour justifier mes griefs sur la syntaxe, je dirais simplement que je ne vois pas pourquoi les routines sont délimitées par des { } et pas les constructions if/for/case, pourquoi le if se termine par fi, le case par esac et le for/while par done et non pas rof/elihw.
penchons-nous sur le problème de l'expansion des variables. Le problème c'est que le shell découpe les mots après l'expansion des variables, c'est à dire que :
var="mot1 mot2"
cmd a b${var}c d
est équivalent à :
cmd a bmot1 mot2c d
et non pas :
cmd a "bmot1 mot2c" d
Alors que dans le code source on ne voit que 3 arguments passés à la commande cmd (a, b${var}c, d), il y en a en fait réellement 4 (a, b$mot1, mot2c, d).
Ce comportement peut être désirable dans certains cas, mais parfois vraiment malvenu. Par exemple lorsqu'on manipule des noms de fichiers contenant des espaces. En gros cela impose lorsqu'on ne sait pas précisément ce qu'il y a dans la variable à toujours l'entourer de quotes, c'est à dire écrire "$var" au lieu de $var.
Non seulement les débutants qui commencent ne comprennent pas toujours cette subtilité et oublient les quotes, mais bien souvent aussi, des gens expérimentés les oublient en les pensant inutiles.
Un exemple concret. la distribution ArchLinux utilise des script bash pour compiler les logiciels et créer des paquets, on les appelle PKGBUILD (un peu similaires aux ebuilds de gentoo). L'exemple le plus courrant et qui sert de modèle à tous les PKGBUILD est¹:
build() {
cd $startdir/src/$pkgname-$pkgver
./configure --prefix=/usr
make || return 1
make prefix=$startdir/pkg/usr install
}
Où $startdir est le dossier dans lequel les sources se trouvent, et où les fichiers sont installés.
Ici on peut voir que $startdir n'est jamais entre quotes, c'est à dire qu'il est impossible de compiler un package si le chemin courrant contient des espaces !!! En effet, la première commande (cd) échoue déjà car au moins deux arguments lui sont passés en paramètres.
C'est ma première critique concernant la robustesse des script shell.
2. La lenteur
Bash, c'est lent. On le voit avec les script d'init, et je l'ai remarqué plus récamment en remplaçant mon script monolithique ~/.xsession par de nombreux scripts modulaires qui me permet à chaque démarrage de:
- me demander mon mot de passe ssh
- lancer quelques programmes comme xbindkeys, mpd
- demander quelle session lancer (E17, GNOME, KDE, Terminal ...)
Et je constate facilement que c'est lent.
Je sais bien que si on veut faire quelque chose de rapide, on utilise plus quelque chose comme python que bash, mais le shell a tout de même l'avantage de pouvoir facilement lancer des applications tierces facilement, éventuellement de manière asynchrone, en modifiant l'environnement, et en redirigeant les entrées/sorties. Si on veut faire la même chose avec un langage classique, je pense que c'est d'un coup moins facile (si on omet la fonction system() qui utilise d'ailleurs le shell).
Sans compter des projets complexe entèrement programmés en bash. Par exemple le gestionnaire de paquets de Nasgaïa est comme ça (ca a peut être changé depuis). Et ne serait-ce qu'afficher l'aide prend un temps fou.
je me demande alors dans quelle mesure (et je vous pose la question) il ne serait pas intéressant d'avoir un interpréteur shell (type sh ou autre) constamment chargé en mémoire qui pourrait rapidement exécuter n'importe quel script. Bien entandu une attention particulière doit être portée à la sécurité.
3. mon code
je vois ai dit que j'avais codé quelque chose, mais quoi ? J'ai commencé un shell basé sur le langage jam². Jam est un remplaçant à make(1) et possède un langage de script qui a les facultés suivantes :
- les variables ne contiennent pas une seule valeur, mais des listes de chaînes de caractères.
- lors de l'expansion des variables est le produit de tous les termes. Pour illustrer cela, je prend juste l'exemple donné dans la documentation³:
$(X) -> a b c
t$(X) -> ta tb tc
$(X).txt -> az bz cz
$(X)-$(X) -> a-a a-b a-c b-a b-b b-c c-a c-b c-c
- la ponctuation n'est pas reconnue si elle n'est pas entourée d'espaces. Cela permet d'avoir de la ponctuation sans problèmes à l'intérieur des mots.
Ce que j'ai fait à partir de ça, c'est relativement simple. J'ai supprimé toute la partie qui s'occupait de la compilation, de la gestion des dépendances entre les cibles, pour ne garder que le langage Jam et faire en sourte que si une fonction n'est pas reconnue de manière interne par Jam, le programme correspondant dans le $PATH soit exécuté. Et cela n'a pris que quelques heures.
Mon code est disponnible sur launchpad⁴ et si cela vous intéresse, plus de détails dans mon e-mais sur la mailing list de jam⁵.
Des remarques ?
¹ http://wiki.archlinux.org/index.php/ABS_-_The_Arch_Build_Sys(...)
² http://freetype.sourceforge.net/jam/index.html
³ http://public.perforce.com/public/jam/src/Jam.html
⁴ https://code.launchpad.net/~mildred/+junk/jam-shell
⁵ http://maillist.perforce.com/pipermail/jamming/2007-November(...)
> Lire le journal (36 commentaires, moyenne: 3,2).
Vous avez demandé le commentaire #881133.



dash
Si bash c'est lent, tu peux essayer dash.
Dash est un shell comptible POSIX, il est beaucoup plus petit que bash, et il execute les script plus rapidement que bash.
C'est le shell utilisé par défaut pour /bin/sh dans Ubuntu.
http://en.wikipedia.org/wiki/Debian_Almquist_shell
[^]Re: Dash vs Linux
second degré :
« Madame Chombier, contre votre baril de Linux je vous offre deux barils de Dash !
- Ah ben nan alors ! Je préfère garder mon baril de Linux. »