- 通过进程控制的学习, 来制作一个minishell
Shell基本上是一个命令解释器,类似于DOS下的command。它接收用户命令(如ls等),然后调用相应的应用程序。
— 百度百科
代码实现
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <sys/wait.h>
int main()
{
while(1)
{
// 1. 等待用户标准输入
printf("[username@localhost]$ ");
fflush(stdout); // 刷新缓冲区, 不换行
char cmd_buf[1024] = {0};
fgets(cmd_buf, 1023, stdin); // 从标准输入读取数据
cmd_buf[strlen(cmd_buf) - 1] = '\0';// cmd_buf最后是一个换行, 把它去掉
// 2. 将输入结果拆分开
char* argv[32] = {NULL};
int argc = 0;
char* ptr = cmd_buf;
while(*ptr != '\0')
{
if (!isspace(*ptr))
{
argv[argc] = ptr;
argc++;
while(!isspace(*ptr) && *ptr != '\0')
{
ptr++;
}
*ptr = '\0';
}
ptr++;
}
argv[argc] = NULL;
int i;
for (i = 0; i < argc; i++)
{
printf("argv[%d]=[%s]\n", i, argv[i]);
}
// 3. 创建子进程, 在子进程中进行程序替换
pid_t pid = fork();
if (pid < 0)
{
// shell不能因为一次出错而退出
continue;
}
else if (pid == 0)
{
// 子进程运行程序
// 使用程序替换
execvp(argv[0], argv);
// 若程序替换失败, 因为子进程运行的代码和父进程的一样
// 替换失败, 则子进程成为了另一个shell
// 这不是想要的, 一个终端不需要多个shell
// 因此替换失败, 则子进程直接退出
exit(0);
}
// shell程序等待子进程退出
wait(NULL);
}
return 0;
}
运行效果
[test@localhost ~]$ make
gcc minishell.c -o minishell
[test@localhost ~]$ ./minishell
[username@localhost]$ ls -a
argv[0]=[ls]
argv[1]=[-a]
. .bash_profile ForkTest minishell .pki test .VimForCpp
.. .bashrc .lesshst minishell.c shm test2 .viminfo
.a.c.swp .cache .LfCache mkfifo signal test2.c .vimrc
.bash_history .config .local .mozilla .ssh test.c .ycm_extra_conf.py
.bash_logout .cquery makefile PipeTest .swp .vim
[username@localhost]$ ls -l
argv[0]=[ls]
argv[1]=[-l]
总用量 52
drwxrwxr-x. 2 test test 100 1月 7 20:18 ForkTest
-rw-rw-r--. 1 test test 97 1月 7 20:52 makefile
-rwxrwxr-x. 1 test test 9064 1月 7 21:33 minishell
-rw-rw-r--. 1 test test 1868 1月 7 21:33 minishell.c
drwxrwxr-x. 2 test test 103 12月 11 16:27 mkfifo
drwxrwxr-x. 2 test test 48 12月 11 15:34 PipeTest
drwxrwxr-x. 3 test test 105 1月 7 12:16 shm
drwxrwxr-x. 2 test test 78 12月 14 21:19 signal
-rwxrwxr-x. 1 test test 8808 12月 1 21:13 test
-rwxrwxr-x. 1 test test 8760 12月 1 21:32 test2
-rw-rw-r--. 1 test test 505 12月 1 21:44 test2.c
-rw-rw-r--. 1 test test 519 12月 1 21:28 test.c
[username@localhost]$ cat test.c
argv[0]=[cat]
argv[1]=[test.c]
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main()
{
int fd;
umask(0);
const char* filename = "/home/test/a.txt";
fd = open(filename, O_RDWR|O_APPEND, 0664);
if (fd < 0)
{
perror("open error!");
return -1;
}
char string[] = "hello IO!\n";
const char* buf = "good!\n";
write(fd, string, strlen(buf));
write(fd, string, strlen(string));
close(fd);
return 0;
}