Pipes, dup2 et exec()
Je dois écrire un shell qui peut exécuter des tuyaux. Par exemple des commandes comme ls -l | wc -l
". J'ai réussi à analyser la commande donnée par l'utilisateur comme ci-dessous:
"ls" = firstcmd
"-l" = frsarg
"wc" = scmd
"-l" = secarg
Maintenant je dois utiliser deux fourches puisque les commandes sont deux et d'un tuyau.
Le bloc de code que j'ai écrit à exec de la commande est la suivante:
pid_t pid;
int fd[2];
pipe(fd);
pid = fork();
if(pid==0)
{
dup2(fd[WRITE_END], STDOUT_FILENO);
close(fd[READ_END]);
execlp(firstcmd, firstcmd, frsarg, (char*) NULL);
}
else
{
pid=fork();
if(pid==0)
{
dup2(fd[READ_END], STDIN_FILENO);
close(fd[WRITE_END]);
execlp(scmd, scmd, secarg, (char*) NULL);
}
}
Donc, quand je lance ma coquille et je entrez la commande ls -l | wc -l
(par exemple) le résultat de la execs n'apparaît pas, mais le shell continue de fonctionner normalement.
La chose étrange est que le résultat de la commande indique que lorsque j'ai résilier mon shell avec "exit" ou "^C".
Quel est le problème avec cette sortie? Pourquoi ne pas apparaître tout de suite après je entrez la commande?
Pouvez-vous modifier mon code pour m'aider à comprendre ce que tu veux dire s'il vous plaît? @Barmar
Règle: si vous dupliquez une extrémité du tuyau à l'entrée standard et la sortie, vous devez fermer les deux extrémités des tubes d'origine avant d'utiliser
exec*()
fonctions (ou continue). Il y a des exceptions; ils sont peu et loin entre. Il est très rare (sur soi, et IRL) que vous rencontrez un programme à l'aide de tuyaux qui ferme trop grand nombre de descripteurs; il est très fréquent de trouver un programme qui n'est pas assez proche de descripteurs. C'est particulièrement courant si il y a plusieurs enfants et/ou de plusieurs tuyaux pour confondre les choses.D'ailleurs, si vous regardez le code dans le github.com/jleffler/soq/tree/master/src/so-4380-8114, vous trouverez un exemple intéressant où "ne ferme pas assez de descripteurs de fichiers causé l'échec du programme sur une assez grande facteurs de production". Lorsque l'entrée était petit, il a bien fonctionné. Lorsque l'entrée est assez grand, le programme coincé dans l'impasse parce que les tuyaux n'ont pas été fermée correctement. (Non, le code de brouillage n'est pas directement sur le Débordement de la Pile.)
OriginalL'auteur Aris Kantas | 2015-11-24
Vous devez vous connecter pour publier un commentaire.
Vous devez fermer tous les tuyaux des descripteurs en tant que le processus père et le processus de l'enfant (après la duplication dans le processus de l'enfant). Dans votre code, le principal problème est que, la
wc
processus n'a pas de sortie car il y a encore des auteurs présents (depuis le processus parent n'a pas fermé la fin d'écriture). Modifications présentées ci-dessous. J'ai également ajouté lawaitpid
dans le processus parent d'attendre lawc
processus.OriginalL'auteur user1969104
Hmm, assez proche. Vous manquez de poignée de fermer certains descripteur de fichier après la fourche.
Voici de référence:
http://www.usna.edu/Users/cs/aviv/classes/ic221/s14/lec/09/lec.html
Voici mon code:
pipe
. Pour résoudre ce problème, vous avez échangéwc
etls
commandes. Enfin, vous n'avez pas fermé les descripteurs du processus parent.Je exécutez votre code et cela a fonctionné, mais j'ai trouvé un autre problème. Pour votre information mon code (trop grand pour l'écrire ici) utilise d'autres execs dans le cas où l'utilisateur ne donne que des "ls" ou "ls-l" ou ls-l /bin". En général, les commandes avec un maximum de deux arguments. Lorsque l'utilisateur lance la commande ls-l | wc-l" tout est ok, le résultat est montré tout de suite, mais quand, après la commande j'essaie seulement de "ls", ou de toute autre commande avec aucun tuyau ne se passe rien. Pourquoi est-ce qui se passe?
Je ne suis pas sûr de ce que vous voulez dire sans voir ton code, mais s'il vous plaît assurez-vous que le tuyau de redirection (l'appel de la pipe, de la fourche, dup2) ne se produit que lorsqu'il y a une deuxième commande donné en argument. Sinon, si vous appelez
execlp("ls","ls","-l",(char*) NULL)
, il n'ya aucune raison pourquoi il n'y a pas de sortie.Notez que
using namespace std;
est une erreur de syntaxe en C, sauf si vous avez une étonnante collection de macros définies sur votre ligne de commande du compilateur (puisque ces macros ne seront pas définis dans le système d'en-têtes). Merci de ne pas poster de code C++ comme une réponse à une question C. Vous avez également plusieurs inutilisés en-têtes dans la liste; ce n'est pas très élégant.<string.h>
,<sys/wait.h>
,<sys/stat.h>
,<termios.h>
, inutilisés, et moderne POSIX ne nécessite pas de<sys/types.h>
être inclus de manière explicite. Vous devriez au moins la sortie siexeclp()
retourne; sans doute, vous devez imprimer un message d'erreur trop.OriginalL'auteur ibrohimislam