Bonjour,
J'aimerais une explication à propos de la fonction moncd en C que je compile et j'exécute par la suite sous shell ou bash.La fonction moncd permet de changer de répertoire courant.
Malheureusement après compilation, ma commande ./moncd ne fonctionne ni sous le shell ni sous bash. Dès que je l'exécute, je n'ai aucun effet et directement c'est le prompt.
La fonction est la suivante:
# include <stdio.h>
# include <unistd.h>
# include <stdlib.h>
int
main(int ac, char * av[]){
char * dir;
int t;
if (ac < 2){
dir = getenv("HOME");
if (dir == 0)
dir = "/tmp";
} else if (ac > 2){
fprintf(stderr, "usage: %s [dir]\n", av[0]);
return 1;
} else
dir = av[1];
t = chdir(dir);
if (t < 0){
perror(dir);
return 1;
}
return 0;
}
Merci de m'aider à comprendre.
# ça fonctionne
Posté par Tonton Benoit . Évalué à 5.
Ton programme fonctionne très bien, d'ailleurs si tu rajoute un getcwd() et affiche le résultat tu verra que le répertoire courant a bien changé à l'intérieur de ton programme.
Et si tu regarde sur ton système tu ne trouvera pas de commande /bin/cd car cette commande est interne à ton shell (bon /bin/cd existe dans la norme POSIX, mais fait la même chose que ton programme)
[^] # Re: ça fonctionne
Posté par roger91 . Évalué à 1. Dernière modification le 03 décembre 2015 à 23:30.
Merci pour la réponse. Donc si j'ai bien compris en gros la commande cd est une commande interne à mon shell.
Mais comment faire justement pour constater ce changement ?
Moi je n'arrive malheureusement pas à le constater.
Quand par exemple j'exécute j'ai ce résultat:
Si elle fonctionne, comment dois-je faire pour constater ce fonctionnement ? Je dois modifier ma fonction en rajoutant la commande getcwd() à l'intérieur ? Si c'est bien cela, à quel niveau de la fonction je dois l'insérer. Si c'est possible d'avoir une illustration avec le code, ça faciliterait ma compréhension.
# ça marche
Posté par benja . Évalué à 3.
Bah ça marche, mais le cwd est uniquement modifé pour ton programme (et ses fils, éventuellement).
Immagine le bordel que ça serait si un processus pouvait modifier l'environement du processu qui l'a lancé ?
Note bien que "cd" est une command interne au shell. Au contraire de ms-dos/windows, qui est donc un système qui ne fourni pas cette "imperméabilité" de l'environement d'exécution du parent par son fils ou sous-fils.
Bref soit tu lance un nouveau shell depuis ton programme, soit tu demande au shell qui lance ton programme d'exécuter quelle que chose à la suite, genre
output=`./monprog|tail -1`; ret=$?; if test $ret eq 42 then eval cd $output; fi
En mieux tu peux utiliser un autre descripteur de sortie pour ne pas devoir réserver ton stdout à cette seule fin. IIRC, certaines distribution configurent un "alias" dans le shell pour midnight commander (mc) afin de pouvoir positionner le répertoire courant du shell sur le dernier visité par mc à la sortie de celui-ci. Tu peux t'inspirer de celà si cela est vraiment nécessaire. Perso, je trouve bizard d'attendre un tel comportement… Dans tout les cas tu devras trouver un système qui demande la coopération du shell appellant :-/[^] # Re: ça marche
Posté par roger91 . Évalué à 1.
Merci pour ta réponse.
Donc l'une des solutions serait de faire une fonction C qui génère un nouveau shell pour l'exécuter avec le programme moncd ? C'est bien cela….
[^] # Commentaire supprimé
Posté par Anonyme . Évalué à 1.
Ce commentaire a été supprimé par l’équipe de modération.
[^] # Re: ça marche
Posté par benja . Évalué à 1. Dernière modification le 04 décembre 2015 à 16:57.
Ok, accordé. Disons que la commande cd aurait très bien pu être externe, voir 2me point.
J'ai bien écris ms-dos/windows, donc implicitement de l'API DOS et des ses implémentations que l'on trouve dans dos >2.0 et windows.
Et là, en dépit de te décevoir, cela n'est pas le cas!
(Au mieux pourrais-tu encore critiquer la pertinence de comparer l'api UNIX à celle de DOS, une api qui n'est certainement plus promue par MS.
J'argumenterais en disais qu'elle est arrivé déjà bien après celle d'UNIX et que cette société aurait pu au moins s'inspirer de l'état de l'art au lieu de torcher un produit dans la seule fin de truster un marcher en faisant fis du développement de l'informatique dans son sens le plus large, quoi que peuvent en dire les médias—encore au jour d'aujourd'hui --.
Je conçois que le posteur de cette question n'a, plus que probablement, aucune expérience avec DOS et donc que cette comparaison s'apparente plus à une expression de type "de mon temps …" sans apporter de vrai valeur pédagogique, néanmoins je souligne ainsi par ce petit retour dans le passé que cette société ne s'est jamais démarquée par l'excellence technique. Car j'estime que sur ce site, il n'est jamais mauvais de faire un peu de prosélytisme, surtout parmi les futurs programmeurs.
Bref, bonjour chez toi et bon week-end)
Et l'âne s'en retourna brouter son herbe…
[^] # Commentaire supprimé
Posté par Anonyme . Évalué à 1.
Ce commentaire a été supprimé par l’équipe de modération.
# Fonction mini shell
Posté par roger91 . Évalué à 1. Dernière modification le 03 décembre 2015 à 23:31.
J'ai finalement résolu mon problème pour le programme moncd précédent merci pour les explications, elles m'ont servi de bcp pour la compréhension.
Par ailleurs, si j'ai un programme C qui a pour but d'exécuter le fonctionnement d'un mini shell comment pourrais je le modifier afin de rajouter la possibilité de lancer des processus en arrière-plan quand la ligne de commande se termine par un & ? L'indication est de ne pas faire le wait dans le parent.
Le but c'est de pouvoir faire un mini shell complet à partir de celui ci voilà pourquoi j'avais besoin de créer un programme moncd pour simuler le fonctionnement de cd.
Le programme est le suivant(il lit une ligne de commande, la découpe avec la fonction découper, fabrique un nouveau processus avec fork et tente d'y lancer la commande en allant chercher un fichier du même nom dans chacun des répertoires indiqué par PATH.):
J'ai pensé à introduire au niveau du parent l'instruction:
Mais l'exécution me produit une erreur.
Merci d'avance …
[^] # Re: Fonction mini shell
Posté par Corentin Rossignon . Évalué à 1.
Réécrire un shell est un très bon exercice pour mieux comprendre les notions de processus et d'environnement sous linux.
Pour le symbole "&", il faut penser à le supprimer de la ligne de commande avant d'appeler execv, le remplacer par un caractère espace est suffisant.
Pour l'arrière plan, il ne faut pas utiliser wait mais faire plusieurs waitpid avec l'option NOHANG (non bloquant) et trouver un moyen de sauvegarder le pid du processus à attendre.
À toi de choisir comment tu souhaites appeler waitpid et surtout à quelle fréquence, certains shell l'appelle après chaque traitement de ligne.
Après si tu as vraiment envie de t'amuser, tu peux commencer à jouer avec la redirection d'entrées-sorties, les pipes, plusieurs processus en arrière plan …
[^] # Re: Fonction mini shell
Posté par roger91 . Évalué à 1.
D'accord je comprends à peu près ce que tu veux dire.
Mais est ce possible d'etre plus explicite de façon concrète avec quelques modifications apportées au niveau de mon code ? sur l'appel du waitpid pour l'arrière plan.
Ca m'éclaircirait davantage. Merci
[^] # Re: Fonction mini shell
Posté par roger91 . Évalué à 1.
" Pour le symbole "&", il faut penser à le supprimer de la ligne de commande avant d'appeler execv, le remplacer par un caractère espace est suffisant."
Qu'est ce que cela voudrait dire ? Sur ma ligne de commande je dois remplacer & par un espace de quelle manière ?
[^] # Re: Fonction mini shell
Posté par Corentin Rossignon . Évalué à 1. Dernière modification le 03 décembre 2015 à 10:20.
Il faut capturer le symbole '&' dans le mot puis le remplacer par un espace (bien) ou un caractère nul (mieux) :
Pour le waitpid, elle diffère de wait en ajoutant la possibilité d'attendre un processus particulier et de spécifier des options d'attente comme NOHANG qui permet de ne pas rester bloqué dans la fonction si le processus fils n'est pas terminé. wait(&status) est équivalent à waitpid(-1, &status, 0).
En remplaçant le paramètre -1 de waitpid par le pid du processus fils, tu n'as plus besoin de faire une boucle while autour de wait.
[^] # Re: Fonction mini shell
Posté par roger91 . Évalué à 1. Dernière modification le 03 décembre 2015 à 23:29.
Merci Corentin !
En tenant compte de tes suggestions, j'ai finalement pu ajouter quelques instructions au niveau du parent:
En essayant quelques exemples sur le mini shell, j'ai ces résultats:
Au vue des résultats, mes instructions sont-elles optimales surtout pour la gestion de plusieurs processus en arrière plan ? Aussi pourquoi en affichant l'echo, il affiche avec le symbole '&' à la fin ? C'est un peu désagréable, comment me débarrasser de cela ? Merci
[^] # Re: Fonction mini shell
Posté par Corentin Rossignon . Évalué à 1.
dois être fait juste avant le execv, dans le fils pas dans le parent.
Pourquoi avoir rajouté un deuxième fork qui fait juste un sleep(2) ?
Pour le mode arrière plan, il faut utiliser :
N'hésite pas à lire le manuel de waitpid pour bien comprendre le fonctionnement.
Le plus dur pour gérer l'arrière plan sera de trouver comment sauvegarder tous les 'tmp' qui représentent les fils en arrière plan. N'hésite pas non plus à renommer tes variables avec des noms compréhensibles, le 'tmp' ne devrait jamais exister dans un programme, tu t'apercevra très vite qu'un bon nom de variable est très pratique.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.