Simulation and implementation of simple Shell under Linux
Full code: https://github.com/JiaZhengJingXianSheng/Linux_Shell
1, fork
Fork system call is used to create a new process, called a child process, which runs simultaneously with the process (called the process of system call fork). This process is called the parent process. After creating a new child process, the two processes will execute the next instruction after the fork () system call. Child processes use the same Program counter , the same CPU register, the same open file used in the parent process.
characteristic
1) In the parent process, fork returns the process ID of the newly created child process;
2) In the subprocess, fork returns 0;
3) If an error occurs, fork returns a negative value;
If the new process is created successfully, two processes will appear, one is the child process and the other is the parent process. In the child process, the fork function returns 0. In the parent process, fork returns the process ID of the newly created child process. Therefore, we can determine whether the process is a child process or a parent process by judging the return value of fork.
2, execvp
execvp() will find the file name matching the parameter file from the directory indicated by PATH, execute the file after finding it, and then pass the second parameter argv to the file to be executed.
If the execution is successful, the function will not return. If the execution fails, it will directly return - 1. The failure reason is stored in errno. We can print the error through the perror() function.
3, wait/waitpid
Wait: once the parent process calls wait, it immediately blocks itself. Wait automatically analyzes whether a child process of the current process has exited. If it finds such a child process that has become a zombie, wait will collect the information of the child process, destroy it completely and return; If such a child process is not found, the wait will block here until one appears.
waitpid: temporarily stop the execution of the current process until a signal comes or the subprocess ends If the child process has ended at the time of call, the child process end status value will be returned immediately The end status value of the child process will be returned by the parameter status, and the process ID of the child process will also be returned quickly
4, Realize
1. Correlation function
pid_t pid = fork();
Call fork function to create a subprocess. The subprocess mentioned here is the thread we usually talk about. However, under Linux, threads are implemented in the form of copy processes, so they are called sub processes here.
int execvp(const char *__file, char *const *__argv)
execvp function can call the command under PATH, where parameter 1 is the opcode (command) and parameter 2 is the opcode + operand (Command + parameter).
perror("fork error");
The eperror function is used to print errors
wait(NULL);
Calling the wait function in the parent process blocks the parent process and checks whether the child process is withdrawn or not, and then the child process is killed.
chdir();
Since the parent process and the child process do not share environment variables, and the child process modifies the environment variables of the current working directory, it has no impact on the parent process. Therefore, the cd command cannot be simply implemented with the execvp function, and the chdir function will be used here.
2. Concrete realization
First read a line of command from the keyboard. The command is divided according to the space. The first parameter is the command and the subsequent parameters are the parameters.
char cmd[64]; cin.getline(cmd, 64);
char *command[64]; const char *s = " "; char *token; /* Get the first substring */ token = strtok(cmd, s); int i = 0; /* Continue to get other substrings */ while (token != NULL) { command[i] = token; token = strtok(NULL, s); i++; } command[i] = NULL;
At this point, we will divide all commands according to format.
Next, let's create a sub thread. In the sub thread, if the command is cd, call chdir(), otherwise call execvp(), and print the error with perror(). Call the wait() function in the parent process to collect the child process back and forth.
if (strcmp(command[0], "exit") == 0) exit(0); pid_t pid = fork(); // Create child process (thread) if (pid == 0) // Subprocess { if (strcmp(command[0], "cd") == 0) // chdir function for cd command chdir(command[1]); else { execvp(command[0], command); perror("fork error"); // execvp failed to execute successfully, fork failed exit(1); } } wait(NULL); // Subprocess death recovery
3. Results
lyz@ubuntu:~/Desktop/LinuxHomework2$ g++ MyShell.cpp -o SHELL lyz@ubuntu:~/Desktop/LinuxHomework2$ ./SHELL Shell>> pwd /home/lyz/Desktop/LinuxHomework2 Shell>> ls MyShell.cpp SHELL Shell>> cd .. Shell>> pwd /home/lyz/Desktop Shell>> exit lyz@ubuntu:~/Desktop/LinuxHomework2$
Our shell is working properly