I am implementing a shell.
When attempting a command other than changing directories, execvp()
runs, the child terminates and a new child is created. When I change directories, the child does not terminate and a new child is created. Here is a sample of my code:
for(;;) { printf("bash: "); parse(); ... pid_t pid = fork() if (pid == 0) if (!strcmp(line[0], "cd")) if (!line[1]) (void) chdir(getenv("HOME")); else (void) chdir(line[1]); else execvp(line[0], line); ... if (pid > 0) { while (pid == wait(NULL)); printf("%d terminated.n", pid); } }
cd ../; ls;
runs correctly, except I have to Ctrl+D
twice to end the program.
Though, if I pipe the same information (ie. mybash < chdirtest
), it runs correctly once, terminates the child, runs again except in the original directly, then terminates the final child.
Advertisement
Answer
cd
should not be invoked through a child process, the shell itself should change its current directory (that’s the property of an internal command: modify the process of the shell itself).
A (primitve) shell should looks like:
for(;;) { printf("bash: "); parse(); // realize internal commands (here "cd") if (!strcmp(line[0], "cd")) { if (!line[1]) (void) chdir(getenv("HOME")); else (void) chdir(line[1]); continue; // jump back to read another command } // realize external commands pid_t pid = fork() if (pid == 0) { execvp(line[0], line); exit(EXIT_FAILURE); // wrong exec } // synchro on child if (pid > 0) { while (pid == wait(NULL)); printf("%d terminated.n", pid); } }