Information Technology Reference
In-Depth Information
main(){
char*prog=NULL;
char**args=NULL;
//readthenextlinefromtheinput,andparseitintotheprogramnameanditsarguments
//returnfalseifwe'vereachedtheendoftheinput
while(readAndParseCmdLine(&prog,&args)){
intchild_pid=fork(); //createachildprocesstorunthecommand
if(child_pid==0){ //I'mthechildprocess
//childusestheparent'sinputandoutput
exec(prog,args); //runtheprogram
//NOTREACHED
}else{
//I'mtheparent
wait(child_pid);
//waitforthechildtocomplete
return0;
}
}
}
Figure3.8: Example code for a simple UNIX shell.
3.3
Case Study: Implementing a shell
The dozen UNIX system calls listed above are enough to build a flexible and
powerful command line shell, one that runs entirely at user-level with no special
permissions. As we mentioned, the process that creates the shell is responsible
for providing it an open file descriptor for reading commands for its input (e.g.,
from the keyboard), called stdin and for writing output (e.g., to the display),
Definition: stdin
called stdout .
Definition: stdout
Figure 3.8 illustrates the code for the basic operation of a shell. The shell
reads a command line from the input, and it forks a process to execute that
command. UNIX fork automatically duplicates all open file descriptors in the
parent, incrementing the kernel's reference counts for those descriptors, so the
input and output of the child is the same as the parent. The parent waits for
the child to finish before it reads the next command to execute.
Because the commands to read and write to an open file descriptor are the
same whether the file descriptor represents a keyboard, screen, file, device, or
pipe, UNIX programs do not need to be aware of where their input is coming
from, or where their output is going. This is helpful in a number of ways:
A program can be a file of commands. Programs are normally a set
of machine instructions, but on UNIX a program can be a file containing a
list of commands for a shell to interpret. To disambiguate, shell programs
signied in UNIX by putting \ #!interpreter " as the rst line of the
le, where \interpreter" is the name of the shell executable.
The UNIX C compiler is structured this way. When it is exec'ed, the
kernel recognizes it as a shell file and starts the interpreter, passing it the
 
Search WWH ::




Custom Search