如何在C程序中退出Busybox环境下的/bin/sh系统shell
Hey there! Let me break down why your current approach isn't working, then walk you through a couple of reliable solutions to fix this.
Why system("exit") Doesn't Work
The system() function creates a brand new child process every time you call it. When you run system("/bin/sh"), that spins up an independent shell process. Later, when you run system("exit"), that's a totally separate, unrelated process—all it does is exit itself, not the shell you launched earlier. That's why it has no effect on the running shell.
Solution 1: Control the Shell via a Pipe (Graceful Exit)
This method lets you send commands directly to the running shell by redirecting its standard input through a pipe. It mimics manually typing exit into the shell, which is the cleanest way to shut it down.
Here's a complete code example:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> int main() { int pipefd[2]; pid_t shell_pid; // Create a pipe to communicate with the shell if (pipe(pipefd) == -1) { perror("Failed to create pipe"); exit(EXIT_FAILURE); } // Fork a child process to run the shell shell_pid = fork(); if (shell_pid == -1) { perror("Failed to fork process"); exit(EXIT_FAILURE); } if (shell_pid == 0) { // Child process: Redirect stdin to the pipe's read end close(pipefd[1]); // Close the unused write end dup2(pipefd[0], STDIN_FILENO); // Replace stdin with pipe read close(pipefd[0]); // Launch Busybox shell execl("/bin/sh", "sh", (char *)NULL); perror("Failed to launch shell"); // Only runs if execl fails exit(EXIT_FAILURE); } else { // Parent process: Send commands to the shell via the pipe close(pipefd[0]); // Close unused read end // Simulate your program doing work before exiting the shell printf("Shell is running... will exit in 5 seconds\n"); sleep(5); // Send the exit command to the shell write(pipefd[1], "exit\n", 5); close(pipefd[1]); // Wait for the shell process to finish wait(NULL); printf("Shell has exited\n"); } return 0; }
How This Works:
- We create a pipe to link the parent C program and the child shell process.
- The shell's standard input is connected to the pipe, so any data we write from the parent gets treated as user input in the shell.
- When we write
exit\nto the pipe, the shell reads it and exits gracefully, just like if you typed the command manually.
Solution 2: Kill the Shell Process (Forced Exit)
If you don't need a graceful shutdown (e.g., the shell doesn't have unsaved state to clean up), you can directly terminate the shell process using a signal. First, you need to track the shell's PID (which system() doesn't give you—so we use fork() + execl() instead):
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> #include <signal.h> int main() { pid_t shell_pid = fork(); if (shell_pid == -1) { perror("Failed to fork process"); exit(EXIT_FAILURE); } if (shell_pid == 0) { // Child process: Launch the shell execl("/bin/sh", "sh", (char *)NULL); perror("Failed to launch shell"); exit(EXIT_FAILURE); } else { // Parent process: Do work, then kill the shell printf("Shell running with PID: %d\n", shell_pid); sleep(5); // Send a termination signal (SIGTERM is graceful; SIGKILL forces it) kill(shell_pid, SIGTERM); wait(NULL); printf("Shell terminated\n"); } return 0; }
Note:
SIGTERMasks the shell to exit cleanly (it can handle cleanup if needed).SIGKILLwill force the shell to exit immediately with no cleanup—use this only ifSIGTERMdoesn't work.
Solution 3: Run Commands and Exit Automatically (Non-Interactive)
If you just need to run a set of commands in the shell and exit immediately (no interactive session), you can pass the commands directly to sh with the -c flag:
#include <stdlib.h> int main() { // Run a sequence of commands then exit system("/bin/sh -c 'echo \"Hello from the shell\"; ls; exit'"); return 0; }
This is great for batch operations where you don't need an interactive shell session.
内容的提问来源于stack exchange,提问作者greenhornprogarammer

