A good way to learn and understand shell -- write your own shell 2

Source: Internet
Author: User
The simplest form of shell scripts is to list a series of commands. Shell acts as an interpreter and runs them one by one until the last or exits. However, this can only be a simple task. It is only the time when the province and province have to run commands one by one. To complete more responsible functions, add these things:
1. Control
What should I do if the preceding conditions are met? What should I do if the conditions are not met.
2. Variables
C = a + B. It represents another form, that is, the variable. Because the form is different, you can use one constant to represent another change. For example, "Programming Language" can be used as a variable and can be assigned to "C", "Perl", and "lisp" languages. The variable can also be understood as a buffer. A cup can be saved with a cup of water, a cup of juice, and a cup of wine. These three names can be classified as the variable name "liquid ".
3. Environment
In fact, the white horse belongs to the horse, and the environment is also a variable. However, it is generally provided by the system to avoid the trouble of setting some variables for each operation of the software, such as setting the language or something. With the environment, these variables can be directly used. The common path, home. Command ENV, shows the environment variables of your system.

The first task is to add command line parsing so that users can enter commands and parameters in a line. The parser splits the input line into a string array and sends it to the execvp of the sub-process.

Let's talk about some signals. A signal is a message composed of a single word. It is used for inter-process communication. A process is running hard. To talk to it, let it exit and pause, you must use a signal. Kill-l allows you to view the signal list.
There are three situations in which processes process signals are processed by default. One is the default processing, which usually disappears. This calls signal (SIGINT, sig_dfl) to restore the default processing of SIGINT; the other is to ignore, call signal (SIGINT, sig_ign) through this; call a function signal (SIGNUM, function );

2) the interrupt signal is sent when you type the intr character (usually Ctrl-C) to notify the foreground process group to terminate the process.

3) sigquit
Similar to SIGINT, but controlled by the quit character (usually Ctrl-\). A process generates a core file when it exits because it receives sigquit.

20) sigtstp stops the process, but the signal can be processed and ignored. This signal is sent when you type the susp character (usually Ctrl-Z ).
In this version of shell, handle SIGINT and sigquit, ignore them in shell, but restore their default operations in sub-shell, in this way, you can end the sub-process in shell instead of killing the shell itself.

The main function of shell is as follows:
/* Chicken_sh.c * shell, chicken. * added command line processing, which is better than egg_sh */# include <stdio. h> # include <stdlib. h> # include <unistd. h> # include <signal. h> # include "smsh. H "# define dfl_prompt"> "Void setup (); void fatal (char * S1, char * S2, int N) int main () {char * character line, * prompt, ** Arglist; int result; prompt = dfl_prompt; setup (); While (Fig line = next_cmd (prompt, stdin ))! = NULL) {If (Arglist = splitline (Response line ))! = NULL) {result = execute (Arglist); freelist (Arglist);} Free (using line);} return 0;} void setup () /* set the signal processing function */{signal (SIGINT, sig_ign); signal (sigquit, sig_ign);} void fatal (char * S1, char * S2, int N) /* error handling function */{fprintf (stderr, "error: % s, % s \ n", S1, S2); exit (n );}



Function explanation:
Next_cmd reads the next command from the input, allocates memory with malloc to accept any length parameter, and returns NULL when the file ends.
The splitline parsing parameter. Splits a string into a string array and returns this array.

Chicken_sh is more complex, so the code is divided into three files: chicken_sh.c, splitline. C, execute. C. (source code download)
Compile as follows:
gcc -o chichen_sh  chicken_sh.c splitline.c execute.c



The execute. C does not change much, but it only adds signal processing.

Splitline. C is a bit complicated. The Code is as follows:
/* Splitline. C * reads and parses the command * char * next_cmd (char * prompt, file * FP) for chicken_sh and obtains the next command * char ** splitline (char * Str ); parses the string */# include <stdio. h> # include <stdlib. h> # include <string. h> # include "chicken_sh.h" char * next_cmd (char * prompt, file * FP) {char * Buf; int bufspace = 0; int Pos = 0; /* Current location */int c; printf ("% s", prompt); While (C = GETC (FP ))! = EOF) {/* If space is required */If (Pos + 1> = bufspace) {If (bufspace = 0) BUF = emalloc (bufsiz ); elsebuf = erealloc (BUF, bufspace + bufsiz);/* expand the allocated memory */bufspace + = bufsiz ;} /* command end */If (C = '\ n') break;/* If not, add it to the buffer */Buf [POS ++] = C ;} if (C = EOF & Pos = 0) return NULL; Buf [POS] = '\ 0'; return Buf ;}# define is_delim (x) (X) = ''| (x) = '\ t')/* The parameter Delimiter is a space or tab */char * newstr (char * s, int L ); char ** spli Tline (char * Line) {char ** ARGs;/* parameter array to be returned */INT spots = 0;/* parameter pointer capacity */INT bufspace = 0; /* buffer space */INT argnum = 0;/* parameter count */char * CP = line; char * start; int Len; If (line = NULL) /* no input */return NULL; ARGs = emalloc (bufsiz);/* allocation parameter array */bufspace = bufsiz; spots = bufsiz/sizeof (char *); while (* CP! = '\ 0') {While (is_delim (* CP) CP ++; If (* CP = "\ 0") break; /* Ensure the space of the parameter array */If (argnum + 1> = spots) {ARGs = erealloc (ARGs, bufspace + bufsiz); bufspace + = bufsiz; spots + = (bufsiz/sizeof (char *);}/* mark the start point and find the position ending with \ 0 */START = CP; Len = 1; while (* ++ CP! = '\ 0 '&&! (Is_delim (* CP) Len ++; ARGs [argnum ++] = newstr (START, Len) ;}args [argnum] = NULL; return ARGs ;} /** construct a string, ending with '\ 0' */char * newstr (char * s, int L) {char * Rv = emalloc (L + 1 ); RV [l] = '\ 0'; strncpy (RV, S, L); Return RV;} After void freelist (char ** list)/* parameter is used up, release space */{char ** CP = List; while (* CP) Free (* CP ++); free (list);} void * emalloc (size_t N) {void * RV; If (Rv = malloc (N) = NULL) fatal ("out of memory", "", 1); Return RV ;} void * erealloc (void * P, size_t N) {void * RV; If (Rv = realloc (p, n) = NULL) fatal ("realloc () failed "," ", 1); Return RV ;}



Emalloc and erealloc are functions used to encapsulate the allocated space for error handling;
Next_cmd accepts the commands and Parameters entered by the user and saves them in a linked list;
Splitline is responsible for splitting accepted parameters into a pointer array separated by each parameter. The space is dynamically allocated, because each parameter is separated by spaces or tabs when you enter a command, newstr Splits them into character-independent strings and ends with '\ 0.

After the chicken_sh is compiled, run the common command and the normal shell, and press Ctrl + D to exit. You can also make the following improvements:
1. Multiple commands in one line, separated by semicolons
2. Add "&" to the end of the background process "&"
3. You can use the exit command to exit. In this way, you can set the exit code, such as exit 1 and exit 0.

Add the if .. Then control statement below
The difference between if in shell and if in C is that if in C is used in a statement or block enclosed by curly brackets, while shell starts with then, "fi" is used to indicate the end of IF, which is simple for the program process design that explains the operation.
In addition, if is based on the assumption that the command exits with 0 to indicate success, for example:
if cat hello.cthenecho hellofi



If the cat command is successfully executed and 0 is returned, the then-to-fi statement block is executed. Note: the return value of the command 0 is different from the value of 0 after the if command. If you want to directly describe true or false, use true or false, if true is equivalent to if followed by a command that is successfully executed. If false, the opposite is true.

It's too long to write the next article...
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.