Bonjour,
J'ai écrit un petit script qui monte un disque dur externe, ouvre une
console et me positionne à la racine du DD. Je voudrais, en plus, qu'il
m'affiche, dans la foulée, un ls -l.
Voilà mon script :
#!/bin/bash
mount /mnt/hd
konsole --workdir /mnt/hd --noclose -e ls -l
Je monte mon HD, j'ouvre une console, mon ls -l est bien affiché... mais la
console est gelée, je ne peux rien en faire sauf la fermer !
Quel conseil pourriez-vous me donner ?
Bonne soirée,
Dominique
#!/bin/bash mount /mnt/hd konsole --workdir /mnt/hd --noclose -e ls -l
konsole, c'est une application kde => x11.
Je monte mon HD, j'ouvre une console, mon ls -l est bien affiché... mais la console est gelée, je ne peux rien en faire sauf la fermer !
Quel conseil pourriez-vous me donner ?
Perso, je modifierais le $HOME/.bashrc pour quelque chose d'approchant. Tu ajoutes tes 2 dernières lignes à la fin du fichier $HOME/.bashrc. Mais là, à chaque ouverture d'un shell tu montes le périphérique...
Bonne soirée,
-- Bruno
Dominique a écrit:
#!/bin/bash
mount /mnt/hd
konsole --workdir /mnt/hd --noclose -e ls -l
konsole, c'est une application kde => x11.
Je monte mon HD, j'ouvre une console, mon ls -l est bien affiché... mais
la console est gelée, je ne peux rien en faire sauf la fermer !
Quel conseil pourriez-vous me donner ?
Perso, je modifierais le $HOME/.bashrc pour quelque chose d'approchant.
Tu ajoutes tes 2 dernières lignes à la fin du fichier $HOME/.bashrc.
Mais là, à chaque ouverture d'un shell tu montes le périphérique...
#!/bin/bash mount /mnt/hd konsole --workdir /mnt/hd --noclose -e ls -l
konsole, c'est une application kde => x11.
Je monte mon HD, j'ouvre une console, mon ls -l est bien affiché... mais la console est gelée, je ne peux rien en faire sauf la fermer !
Quel conseil pourriez-vous me donner ?
Perso, je modifierais le $HOME/.bashrc pour quelque chose d'approchant. Tu ajoutes tes 2 dernières lignes à la fin du fichier $HOME/.bashrc. Mais là, à chaque ouverture d'un shell tu montes le périphérique...
Bonne soirée,
-- Bruno
Dominique
Bruno Mathieu wrote:
konsole, c'est une application kde => x11.
Exact.
Mais là, à chaque ouverture d'un shell tu montes le périphérique...
C'est ce que je voudrais éviter. Je ne souhaite monter mon disque qu'à la demande. Bonne soirée, Dominique
Bruno Mathieu wrote:
konsole, c'est une application kde => x11.
Exact.
Mais là, à chaque ouverture d'un shell tu montes le périphérique...
C'est ce que je voudrais éviter. Je ne souhaite monter mon disque qu'à la
demande.
Bonne soirée,
Dominique
Tu peux nous donner la syntaxe que la doc propose pour l'argument après '-e' ?
C'est certainement la même que pour xterm, à savoir la liste des arguments à passer à l'appel système exec.
Parceque tu peux par exemple faire un '-e (ls -l ; /bin/sh)' , ce qui te donnerai un prompt directement après le 'ls -l'.
Il y a très peu de chances que ça marche. En revanche, ceci marchera certainement :
-e sh -c 'ls -l; exec $SHELL'
Rakotomandimby Mihamina
On Sun, 31 Oct 2004 15:44:27 +0100, Bruno Mathieu wrote:
Dominique a écrit:
#!/bin/bash mount /mnt/hd konsole --workdir /mnt/hd --noclose -e ls -l
Tu peux nous donner la syntaxe que la doc propose pour l'argument après '-e' ?
Parceque tu peux par exemple faire un '-e (ls -l ; /bin/sh)' , ce qui te donnerai un prompt directement après le 'ls -l'.
Mais ça dépend de la syntaxe. -- ASPO Infogérance - http://aspo.rktmb.org/activites/infogerance Unofficial FAQ fcolc - http://faq.fcolc.eu.org/ Linux User Group sur Orléans et alentours. Tél: + 33 2 38 76 43 65 (France)
On Sun, 31 Oct 2004 15:44:27 +0100, Bruno Mathieu wrote:
Dominique a écrit:
#!/bin/bash
mount /mnt/hd
konsole --workdir /mnt/hd --noclose -e ls -l
Tu peux nous donner la syntaxe que la doc propose pour l'argument après
'-e' ?
Parceque tu peux par exemple faire un '-e (ls -l ; /bin/sh)' , ce qui te
donnerai un prompt directement après le 'ls -l'.
Mais ça dépend de la syntaxe.
--
ASPO Infogérance - http://aspo.rktmb.org/activites/infogerance
Unofficial FAQ fcolc - http://faq.fcolc.eu.org/
Linux User Group sur Orléans et alentours.
Tél: + 33 2 38 76 43 65 (France)
On Sun, 31 Oct 2004 15:44:27 +0100, Bruno Mathieu wrote:
Dominique a écrit:
#!/bin/bash mount /mnt/hd konsole --workdir /mnt/hd --noclose -e ls -l
Tu peux nous donner la syntaxe que la doc propose pour l'argument après '-e' ?
Parceque tu peux par exemple faire un '-e (ls -l ; /bin/sh)' , ce qui te donnerai un prompt directement après le 'ls -l'.
Mais ça dépend de la syntaxe. -- ASPO Infogérance - http://aspo.rktmb.org/activites/infogerance Unofficial FAQ fcolc - http://faq.fcolc.eu.org/ Linux User Group sur Orléans et alentours. Tél: + 33 2 38 76 43 65 (France)
Bruno Mathieu
Dominique a écrit:
Bruno Mathieu wrote:
konsole, c'est une application kde => x11.
Exact.
Mais là, à chaque ouverture d'un shell tu montes le périphérique...
C'est ce que je voudrais éviter. Je ne souhaite monter mon disque qu'à la demande.
Dans $HOME.bashrc, tu encapsule tes lignes dans un if
if [ O$TOTO == O ]; then ...; fi
Ensuite tu crées un fichier "lien vers une appli" dans kde, avec la propriété Commande : "TOTO=x konsole" Ça passera la variable TOTO à l'environnement et en fonction tu fais ce que tu veux.
Bonne soirée, Dominique
Bonne soirée. -- Bruno
Dominique a écrit:
Bruno Mathieu wrote:
konsole, c'est une application kde => x11.
Exact.
Mais là, à chaque ouverture d'un shell tu montes le périphérique...
C'est ce que je voudrais éviter. Je ne souhaite monter mon disque qu'à la
demande.
Dans $HOME.bashrc, tu encapsule tes lignes dans un if
if [ O$TOTO == O ]; then ...; fi
Ensuite tu crées un fichier "lien vers une appli" dans kde, avec la
propriété Commande : "TOTO=x konsole" Ça passera la variable TOTO à
l'environnement et en fonction tu fais ce que tu veux.
Mais là, à chaque ouverture d'un shell tu montes le périphérique...
C'est ce que je voudrais éviter. Je ne souhaite monter mon disque qu'à la demande.
Dans $HOME.bashrc, tu encapsule tes lignes dans un if
if [ O$TOTO == O ]; then ...; fi
Ensuite tu crées un fichier "lien vers une appli" dans kde, avec la propriété Commande : "TOTO=x konsole" Ça passera la variable TOTO à l'environnement et en fonction tu fais ce que tu veux.
Bonne soirée, Dominique
Bonne soirée. -- Bruno
Dominique
Rakotomandimby Mihamina wrote:
Tu peux nous donner la syntaxe que la doc propose pour l'argument après '-e' ? konsole --help :
-e <command> Exécute «command» à la place du shell
Parceque tu peux par exemple faire un '-e (ls -l ; /bin/sh)' , ce qui te donnerai un prompt directement après le 'ls -l'.
Ca a l'air de lui faire tout drôle (hd, c'est le nom de mon script) :
[ messcripts]$ ./hd ./hd: line 3: syntax error near unexpected token `(' ./hd: line 3: `konsole --workdir /mnt/hd -e (ls -l ; /bin/sh)'
Visiblement, le bash n'aime pas les parenthèses.
Mais ça dépend de la syntaxe.
C'est sûr. Je ne dois pas être loin de la solution mais je ne la vois pas. Si je remplace les parenthèses par des guillements, il y a un Fail exec et ma console est plantée.
Merci, Dominique
Rakotomandimby Mihamina wrote:
Tu peux nous donner la syntaxe que la doc propose pour l'argument après
'-e' ?
konsole --help :
-e <command> Exécute «command» à la place du shell
Parceque tu peux par exemple faire un '-e (ls -l ; /bin/sh)' , ce qui te
donnerai un prompt directement après le 'ls -l'.
Ca a l'air de lui faire tout drôle (hd, c'est le nom de mon script) :
[normal@localhost messcripts]$ ./hd
./hd: line 3: syntax error near unexpected token `('
./hd: line 3: `konsole --workdir /mnt/hd -e (ls -l ; /bin/sh)'
Visiblement, le bash n'aime pas les parenthèses.
Mais ça dépend de la syntaxe.
C'est sûr. Je ne dois pas être loin de la solution mais je ne la vois pas.
Si je remplace les parenthèses par des guillements, il y a un Fail exec et
ma console est plantée.
Tu peux nous donner la syntaxe que la doc propose pour l'argument après '-e' ? konsole --help :
-e <command> Exécute «command» à la place du shell
Parceque tu peux par exemple faire un '-e (ls -l ; /bin/sh)' , ce qui te donnerai un prompt directement après le 'ls -l'.
Ca a l'air de lui faire tout drôle (hd, c'est le nom de mon script) :
[ messcripts]$ ./hd ./hd: line 3: syntax error near unexpected token `(' ./hd: line 3: `konsole --workdir /mnt/hd -e (ls -l ; /bin/sh)'
Visiblement, le bash n'aime pas les parenthèses.
Mais ça dépend de la syntaxe.
C'est sûr. Je ne dois pas être loin de la solution mais je ne la vois pas. Si je remplace les parenthèses par des guillements, il y a un Fail exec et ma console est plantée.
Merci, Dominique
Dominique
Nicolas George wrote:
Il y a très peu de chances que ça marche. En revanche, ceci marchera certainement :
-e sh -c 'ls -l; exec $SHELL'
Et ça marche même très bien ! Merci. J'ai ma réponse. Est-ce que tu pourrais m'expliquer pourquoi cette ligne marche et pourquoi mes essais, eux, ne marchaient pas ?
Dominique
Nicolas George wrote:
Il y a très peu de chances que ça marche. En revanche, ceci marchera
certainement :
-e sh -c 'ls -l; exec $SHELL'
Et ça marche même très bien ! Merci. J'ai ma réponse.
Est-ce que tu pourrais m'expliquer pourquoi cette ligne marche et pourquoi
mes essais, eux, ne marchaient pas ?
Il y a très peu de chances que ça marche. En revanche, ceci marchera certainement :
-e sh -c 'ls -l; exec $SHELL'
Et ça marche même très bien ! Merci. J'ai ma réponse. Est-ce que tu pourrais m'expliquer pourquoi cette ligne marche et pourquoi mes essais, eux, ne marchaient pas ?
Dominique
Vincent Bernat
OoO Lors de la soirée naissante du dimanche 31 octobre 2004, vers 17:26, Bruno Mathieu disait:
if [ O$TOTO == O ]; then ...; fi
On préférera :
if [[ -z $TOTO ]]; then ... ; fi -- panic("esp_handle: current_SC == penguin within interrupt!"); 2.2.16 /usr/src/linux/drivers/scsi/esp.c
OoO Lors de la soirée naissante du dimanche 31 octobre 2004, vers
17:26, Bruno Mathieu <bruno.mathieu@freesurf.fr> disait:
if [ O$TOTO == O ]; then ...; fi
On préférera :
if [[ -z $TOTO ]]; then ... ; fi
--
panic("esp_handle: current_SC == penguin within interrupt!");
2.2.16 /usr/src/linux/drivers/scsi/esp.c
OoO Lors de la soirée naissante du dimanche 31 octobre 2004, vers 17:26, Bruno Mathieu disait:
if [ O$TOTO == O ]; then ...; fi
On préférera :
if [[ -z $TOTO ]]; then ... ; fi -- panic("esp_handle: current_SC == penguin within interrupt!"); 2.2.16 /usr/src/linux/drivers/scsi/esp.c
Bruno Mathieu
Vincent Bernat a écrit:
if [ O$TOTO == O ]; then ...; fi
On préférera :
if [[ -z $TOTO ]]; then ... ; fi
Merci Vincent, j'oublie à chaque fois et je fais la sale méthode :-/ L'avantage de la solution de Nicolas (sh -c 'ls -l; exec $SHELL') est qu'elle est quand même plus portable que mon brouillon !
-- Bruno
Vincent Bernat a écrit:
if [ O$TOTO == O ]; then ...; fi
On préférera :
if [[ -z $TOTO ]]; then ... ; fi
Merci Vincent, j'oublie à chaque fois et je fais la sale méthode :-/
L'avantage de la solution de Nicolas (sh -c 'ls -l; exec $SHELL') est
qu'elle est quand même plus portable que mon brouillon !
Merci Vincent, j'oublie à chaque fois et je fais la sale méthode :-/ L'avantage de la solution de Nicolas (sh -c 'ls -l; exec $SHELL') est qu'elle est quand même plus portable que mon brouillon !
-- Bruno
Nicolas George
Dominique wrote in message <41851b5a$0$3672$:
Et ça marche même très bien ! Merci. J'ai ma réponse. Est-ce que tu pourrais m'expliquer pourquoi cette ligne marche et pourquoi mes essais, eux, ne marchaient pas ?
Pas de problème, mais il faut partir des bases. Quand un programme est lancé, il s'agit d'un chemin vers un binaire, plus une liste d'arguments qui sont des chaînes de caractères, brutes et sans interprétation. C'est l'appel système execve qui fait ça. Tout ce qui est spécial dans une ligne de commande est fait par le shell. Ainsi, quand on tape :
rm *.mp3; ls *.ogg
le shell fait ceci successivement :
- il détecte le point-virgule, caractère spécial, et coupe la ligne en deux ;
- il détecte l'espace après rm, et le prend comme la séparation entre le nom de la commande et un argument ;
- il détecte l'étoile, et remplace *.mp3 par la liste des fichier reconnus ;
- il cherche rm dans le PATH ;
- il exécute la commande ainsi construite, qui va être quelque chose comme, en notation C :
- execl est une fonction pratique par rapport à execve qui accepte ses les arguments de la commande directement dans la liste des arguments, avec NULL pour marquer la fin. Normalement, avec execve, il faut construire un tableau et passer un pointeur sur ce tableau (et passer un pointeur sur le tableau de l'environnement également). D'ailleurs, un shell va systématiquement utiliser execve plutôt qu'execl, puisqu'il doit construire le tableau des arguments à l'exécution.
- Par convention, toutes les commandes reçoivent en premier argument le nom de la commande, ce qui explique pourquoi la commande a à la fois /bin/rm et rm. La plupart du temps, elles l'ignorent simplement, mais certaines adaptent leur comportement, comme gzip, qui compresse quand son premier argument est gzip, et décompresse quand il est gunzip.
Maintenant, que fait xterm, ou konsole ? Il ouvre une fenêtre, exécute une commande en établissant un canal de communication (un pseudo-terminal) avec elle, affiche tout ce que lui dit la commande, et transmet à la commande ce que l'utilisateur tape au clavier. Quand la commande se termine, xterm se ferme.
Quelle commande est exécutée ? Par défaut, c'est le contenu de la variable d'environnement $SHELL, sans arguments supplémentaires. Normalement, ça correspond à un programme qui affiche un prompt, lit des commandes et les exécute, un shell interactif.
Mais ça peut être changé par l'option -e. Que prend l'option -e ? Pas une vraie ligne de commande, car il faudrait embarquer un shell dans xterm, ce qui serait lourd et pénible. Au contraire, xterm prend ce qui suit -e comme une liste d'arguments constituant une ligne de commande déjà construite. Ainsi, si l'on tape :
xterm -e vim *.tex
xterm verra ces arguments-là, passés par le shell où on a tapé ça :
xterm -e vim foo.tex bar.tex
et exécutera :
vim foo.tex bar.tex
Ce qui est exactement ce qu'on attendait de lui. Mais ça marche parce que l'étoile a un comportement sympa de ce point de vue. Si on écrit ceci :
xterm -e vim foo.tex; latex foo.tex
alors le shell découpe la ligne au point-virgule avant de considérer la commande xterm, puis il exécute :
xterm -e vim foo.tex
et xterm ne voit jamais le point-virgule. D'ailleurs, il n'aurait pas su quoi en faire. Si on essaie, par exemple :
xterm -e vim foo.tex ';' latex foo.tex
pour forcer le point-virgule à être passé à xterm, alors xterm va exécuter
c'est à dire lancer vim sur le fichier foo.tex (deux fois), le fichier latex, et le fichier « ; ».
On ne peut pas en sortir, xterm ne sait exécuter qu'un seul programme. Cependant, on peut en sortir, il suffit de faire un script. Si on colle dans un script :
#!/bin/sh vim foo.tex latex foo.tex
et qu'on lance
xterm -e ./ce_script
alors xterm exécute ce script, un seul programme, et c'est ce script (en fait, un /bin/sh qui est en train de l'interpréter) qui lui-même exécute successivement vim et latex.
On peut faire l'économie du fichier pour le script si on sait que la plupart des shells, dont sh, savent prendre en argument une ligne de commande qu'ils doivent décomposer de manière habituelle et exécuter; C'est l'option qui fait ça. Donc plutôt que de faire un script, on peut taper :
xterm -e sh -c 'vim foo.tex; latex foo.tex'
Maintenant, le but initial, c'était d'avoir ls, puis une invite de commande, et pas vim puis latex. ls, ben c'est ls, l'invite de commande, c'est $SHELL (souvent /bin/bash sous Linux, on se demande pourquoi, et en tout cas ce n'est pas systématiquement ça, donc il vaut mieux utiliser $SHELL). Donc ça devient :
xterm -e sh -c 'ls; $SHELL'
Reste le petit détail : l'exec :
xterm -e sh -c 'ls; exec $SHELL'
Il dit au sh qui est en train de faire le -c qu'il ne doit pas lancer $SHELL dans un nouveau processus, mais l'exécuter à la place de lui-même. Ainsi, au lieu d'avoir :
- xterm - xterm _ sh -c puis _ sh -c _ ls _ $SHELL
on a :
- xterm - xterm _ sh -c puis _ $SHELL _ ls
Ça économise de la mémoire et du CPU (et c'est aussi mieux pour des histoires de sessions de processus, mais je ne vais pas en parler).
Quant à la version avec les parenthèses, la parenthèse est un caractère spécial pour beaucoup de shell, qui ne peut pas se placer n'importe où.
Dominique wrote in message <41851b5a$0$3672$8fcfb975@news.wanadoo.fr>:
Et ça marche même très bien ! Merci. J'ai ma réponse.
Est-ce que tu pourrais m'expliquer pourquoi cette ligne marche et pourquoi
mes essais, eux, ne marchaient pas ?
Pas de problème, mais il faut partir des bases. Quand un programme est
lancé, il s'agit d'un chemin vers un binaire, plus une liste d'arguments qui
sont des chaînes de caractères, brutes et sans interprétation. C'est l'appel
système execve qui fait ça. Tout ce qui est spécial dans une ligne de
commande est fait par le shell. Ainsi, quand on tape :
rm *.mp3; ls *.ogg
le shell fait ceci successivement :
- il détecte le point-virgule, caractère spécial, et coupe la ligne en
deux ;
- il détecte l'espace après rm, et le prend comme la séparation entre le nom
de la commande et un argument ;
- il détecte l'étoile, et remplace *.mp3 par la liste des fichier reconnus ;
- il cherche rm dans le PATH ;
- il exécute la commande ainsi construite, qui va être quelque chose comme,
en notation C :
- execl est une fonction pratique par rapport à execve qui accepte ses les
arguments de la commande directement dans la liste des arguments, avec
NULL pour marquer la fin. Normalement, avec execve, il faut construire
un tableau et passer un pointeur sur ce tableau (et passer un pointeur
sur le tableau de l'environnement également). D'ailleurs, un shell va
systématiquement utiliser execve plutôt qu'execl, puisqu'il doit
construire le tableau des arguments à l'exécution.
- Par convention, toutes les commandes reçoivent en premier argument le
nom de la commande, ce qui explique pourquoi la commande a à la fois
/bin/rm et rm. La plupart du temps, elles l'ignorent simplement, mais
certaines adaptent leur comportement, comme gzip, qui compresse quand
son premier argument est gzip, et décompresse quand il est gunzip.
Maintenant, que fait xterm, ou konsole ? Il ouvre une fenêtre, exécute une
commande en établissant un canal de communication (un pseudo-terminal) avec
elle, affiche tout ce que lui dit la commande, et transmet à la commande ce
que l'utilisateur tape au clavier. Quand la commande se termine, xterm se
ferme.
Quelle commande est exécutée ? Par défaut, c'est le contenu de la variable
d'environnement $SHELL, sans arguments supplémentaires. Normalement, ça
correspond à un programme qui affiche un prompt, lit des commandes et les
exécute, un shell interactif.
Mais ça peut être changé par l'option -e. Que prend l'option -e ? Pas une
vraie ligne de commande, car il faudrait embarquer un shell dans xterm, ce
qui serait lourd et pénible. Au contraire, xterm prend ce qui suit -e comme
une liste d'arguments constituant une ligne de commande déjà construite.
Ainsi, si l'on tape :
xterm -e vim *.tex
xterm verra ces arguments-là, passés par le shell où on a tapé ça :
xterm -e vim foo.tex bar.tex
et exécutera :
vim foo.tex bar.tex
Ce qui est exactement ce qu'on attendait de lui. Mais ça marche parce que
l'étoile a un comportement sympa de ce point de vue. Si on écrit ceci :
xterm -e vim foo.tex; latex foo.tex
alors le shell découpe la ligne au point-virgule avant de considérer la
commande xterm, puis il exécute :
xterm -e vim foo.tex
et xterm ne voit jamais le point-virgule. D'ailleurs, il n'aurait pas su
quoi en faire. Si on essaie, par exemple :
xterm -e vim foo.tex ';' latex foo.tex
pour forcer le point-virgule à être passé à xterm, alors xterm va exécuter
c'est à dire lancer vim sur le fichier foo.tex (deux fois), le fichier
latex, et le fichier « ; ».
On ne peut pas en sortir, xterm ne sait exécuter qu'un seul programme.
Cependant, on peut en sortir, il suffit de faire un script. Si on colle dans
un script :
#!/bin/sh
vim foo.tex
latex foo.tex
et qu'on lance
xterm -e ./ce_script
alors xterm exécute ce script, un seul programme, et c'est ce script (en
fait, un /bin/sh qui est en train de l'interpréter) qui lui-même exécute
successivement vim et latex.
On peut faire l'économie du fichier pour le script si on sait que la plupart
des shells, dont sh, savent prendre en argument une ligne de commande qu'ils
doivent décomposer de manière habituelle et exécuter; C'est l'option qui
fait ça. Donc plutôt que de faire un script, on peut taper :
xterm -e sh -c 'vim foo.tex; latex foo.tex'
Maintenant, le but initial, c'était d'avoir ls, puis une invite de commande,
et pas vim puis latex. ls, ben c'est ls, l'invite de commande, c'est $SHELL
(souvent /bin/bash sous Linux, on se demande pourquoi, et en tout cas ce
n'est pas systématiquement ça, donc il vaut mieux utiliser $SHELL). Donc ça
devient :
xterm -e sh -c 'ls; $SHELL'
Reste le petit détail : l'exec :
xterm -e sh -c 'ls; exec $SHELL'
Il dit au sh qui est en train de faire le -c qu'il ne doit pas lancer $SHELL
dans un nouveau processus, mais l'exécuter à la place de lui-même. Ainsi, au
lieu d'avoir :
- xterm - xterm
_ sh -c puis _ sh -c
_ ls _ $SHELL
on a :
- xterm - xterm
_ sh -c puis _ $SHELL
_ ls
Ça économise de la mémoire et du CPU (et c'est aussi mieux pour des
histoires de sessions de processus, mais je ne vais pas en parler).
Quant à la version avec les parenthèses, la parenthèse est un caractère
spécial pour beaucoup de shell, qui ne peut pas se placer n'importe où.
Et ça marche même très bien ! Merci. J'ai ma réponse. Est-ce que tu pourrais m'expliquer pourquoi cette ligne marche et pourquoi mes essais, eux, ne marchaient pas ?
Pas de problème, mais il faut partir des bases. Quand un programme est lancé, il s'agit d'un chemin vers un binaire, plus une liste d'arguments qui sont des chaînes de caractères, brutes et sans interprétation. C'est l'appel système execve qui fait ça. Tout ce qui est spécial dans une ligne de commande est fait par le shell. Ainsi, quand on tape :
rm *.mp3; ls *.ogg
le shell fait ceci successivement :
- il détecte le point-virgule, caractère spécial, et coupe la ligne en deux ;
- il détecte l'espace après rm, et le prend comme la séparation entre le nom de la commande et un argument ;
- il détecte l'étoile, et remplace *.mp3 par la liste des fichier reconnus ;
- il cherche rm dans le PATH ;
- il exécute la commande ainsi construite, qui va être quelque chose comme, en notation C :
- execl est une fonction pratique par rapport à execve qui accepte ses les arguments de la commande directement dans la liste des arguments, avec NULL pour marquer la fin. Normalement, avec execve, il faut construire un tableau et passer un pointeur sur ce tableau (et passer un pointeur sur le tableau de l'environnement également). D'ailleurs, un shell va systématiquement utiliser execve plutôt qu'execl, puisqu'il doit construire le tableau des arguments à l'exécution.
- Par convention, toutes les commandes reçoivent en premier argument le nom de la commande, ce qui explique pourquoi la commande a à la fois /bin/rm et rm. La plupart du temps, elles l'ignorent simplement, mais certaines adaptent leur comportement, comme gzip, qui compresse quand son premier argument est gzip, et décompresse quand il est gunzip.
Maintenant, que fait xterm, ou konsole ? Il ouvre une fenêtre, exécute une commande en établissant un canal de communication (un pseudo-terminal) avec elle, affiche tout ce que lui dit la commande, et transmet à la commande ce que l'utilisateur tape au clavier. Quand la commande se termine, xterm se ferme.
Quelle commande est exécutée ? Par défaut, c'est le contenu de la variable d'environnement $SHELL, sans arguments supplémentaires. Normalement, ça correspond à un programme qui affiche un prompt, lit des commandes et les exécute, un shell interactif.
Mais ça peut être changé par l'option -e. Que prend l'option -e ? Pas une vraie ligne de commande, car il faudrait embarquer un shell dans xterm, ce qui serait lourd et pénible. Au contraire, xterm prend ce qui suit -e comme une liste d'arguments constituant une ligne de commande déjà construite. Ainsi, si l'on tape :
xterm -e vim *.tex
xterm verra ces arguments-là, passés par le shell où on a tapé ça :
xterm -e vim foo.tex bar.tex
et exécutera :
vim foo.tex bar.tex
Ce qui est exactement ce qu'on attendait de lui. Mais ça marche parce que l'étoile a un comportement sympa de ce point de vue. Si on écrit ceci :
xterm -e vim foo.tex; latex foo.tex
alors le shell découpe la ligne au point-virgule avant de considérer la commande xterm, puis il exécute :
xterm -e vim foo.tex
et xterm ne voit jamais le point-virgule. D'ailleurs, il n'aurait pas su quoi en faire. Si on essaie, par exemple :
xterm -e vim foo.tex ';' latex foo.tex
pour forcer le point-virgule à être passé à xterm, alors xterm va exécuter
c'est à dire lancer vim sur le fichier foo.tex (deux fois), le fichier latex, et le fichier « ; ».
On ne peut pas en sortir, xterm ne sait exécuter qu'un seul programme. Cependant, on peut en sortir, il suffit de faire un script. Si on colle dans un script :
#!/bin/sh vim foo.tex latex foo.tex
et qu'on lance
xterm -e ./ce_script
alors xterm exécute ce script, un seul programme, et c'est ce script (en fait, un /bin/sh qui est en train de l'interpréter) qui lui-même exécute successivement vim et latex.
On peut faire l'économie du fichier pour le script si on sait que la plupart des shells, dont sh, savent prendre en argument une ligne de commande qu'ils doivent décomposer de manière habituelle et exécuter; C'est l'option qui fait ça. Donc plutôt que de faire un script, on peut taper :
xterm -e sh -c 'vim foo.tex; latex foo.tex'
Maintenant, le but initial, c'était d'avoir ls, puis une invite de commande, et pas vim puis latex. ls, ben c'est ls, l'invite de commande, c'est $SHELL (souvent /bin/bash sous Linux, on se demande pourquoi, et en tout cas ce n'est pas systématiquement ça, donc il vaut mieux utiliser $SHELL). Donc ça devient :
xterm -e sh -c 'ls; $SHELL'
Reste le petit détail : l'exec :
xterm -e sh -c 'ls; exec $SHELL'
Il dit au sh qui est en train de faire le -c qu'il ne doit pas lancer $SHELL dans un nouveau processus, mais l'exécuter à la place de lui-même. Ainsi, au lieu d'avoir :
- xterm - xterm _ sh -c puis _ sh -c _ ls _ $SHELL
on a :
- xterm - xterm _ sh -c puis _ $SHELL _ ls
Ça économise de la mémoire et du CPU (et c'est aussi mieux pour des histoires de sessions de processus, mais je ne vais pas en parler).
Quant à la version avec les parenthèses, la parenthèse est un caractère spécial pour beaucoup de shell, qui ne peut pas se placer n'importe où.