Shell is like the editor: everyone has their own choice and tries to defend the choice (it also tells you why the choice should be used ). Indeed, s
Shell is like the editor: everyone has their own choice and tries to defend the choice (it also tells you why the choice should be used ). Indeed, shell provides different functions, but they all implement the core concept of development decades ago.
I used modern shell for the first time in 1980s, when I was developing software on SunOS. When I learned how to use the output of one program as the input of another program (or even multiple links, I have a simple and efficient way to create filters and conversions. This core concept provides a way to build some simple tools that are flexible enough to work with other tools. In this way, shell not only provides a way to interact with the kernel and the device, but also provides integrated services (such as pipelines and filters) as common design patterns in software development ).
Let's first briefly introduce the development history of modern shell, and then explore some useful shells that can be used in Linux.
Shell Development history
Shell (or command line interpreter) has a long history, but we will discuss from the first UNIX®Shell. Ken Thompson developed the first UNIX shell named V6 shell in 1971. Similar to its predecessor in Multics, this shell (/bin/sh) is an independent user program executed outside the kernel. Globbing (parameter extension pattern matching, such as *. txt) is implemented in an independent utility named glob, just like the if command used to evaluate the conditional expression. This independence can keep shell small, with less than 900 lines of C source code (see references for links to obtain the original source code ).
This shell introduces a compact syntax for redirection (<> and>) and pipeline (| or ^), which has been extended to modern shell. You can also find the support for calling sequential commands (use;) and asynchronous commands (use.
What Thompson shell lacks is the ability to write scripts. It is used as an interactive shell (command interpreter) to call commands and view results.
UNIX shell since 1977
Aside from the Thompson shell, we began to look at the modern shell introduced when the Bourne shell was introduced in 1977. The Bourne shell was created by Stephen Bourne at AT&T Bell Labs for V7 UNIX and is still a useful shell (in some cases also used as the default root shell ). The author developed the Bourne shell after studying the ALGOL68 compiler, so you will find that its syntax is more similar to Algorithmic Language (ALGOL) than other shells ). Despite C development, the source code itself even uses macros to give it an ALGOL68 feature.
The Bourne shell has two main goals: to use it as a command interpreter to execute interactive operating system commands and to write scripts (to compile reusable scripts that can be called by shell ). In addition to replacing Thompson shell, Bourne shell also provides multiple advantages over its predecessor. Bourne introduces control flows, loops, and variables to the script, providing a more powerful language for interacting with the operating system (including interactive and non-interactive ). This shell also allows you to use shell scripts as filters to provide support for signal processing integration, but lacks the ability to define functions. Finally, it integrates many of the features we are using today, including command replacement (using reverse quotation marks) and the HERE document used to embed the reserved string text into the script.
The Bourne shell is not only an important step forward, but also the basis for many derivative shells, many of which are now applied in typical Linux systems. Figure 1 demonstrates the series of important shells. The Bourne shell leads to the development of the Korn shell (ksh), almshells (ash), and popular Bourne Again shell (or Bash. C shell (csh) is under development when the Bourne shell is released. Figure 1 shows the main series, but does not show all the influences, and does not show shell with significant contributions.
Figure 1. Linux shell since 1977
We will analyze some of the shells later to view the language and function examples that contribute to their progress.
Basic shell architecture
The basic architecture of a hypothetical shell is very simple (the shell of Bourne is a piece of evidence ). As you can see in Figure 2, the basic architecture looks like a pipe, which analyzes and parses the input and expands the symbol (using various methods, for example, parentheses, tildes, variables, parameter extensions and replacements, and file name generation), and finally execute commands (using shell built-in commands or external commands ).
Figure 2. simple architecture of hypothetical shell
In the references section, you can find some links to learn about the open source Bash shell architecture.
Explore Linux shell
Now let's look at some of the shells, review their contributions and view the sample scripts in each shell. You can view C shell, Korn shell, and Bash.
Tenex C shell
C shell was developed for the Berkeley SoftwareDistribution (BSD) UNIX system at the University of California at Berkeley in 1978. Five years later, the shell introduced features from the Tenex system (popular on the dec pdp system. Tenex introduces the file name and command completion functions, as well as the command line editing function. Tenex C shell (tcsh) is still backward compatible with csh, but it improves its overall interactive function. Tcsh was developed by Ken Greer at Carnegie Mellon University.
An important design goal of the C shell is to create a scripting language similar to the C language. This is a useful goal, because C is the main language used (in addition, the operating system is mainly developed using C language ).
One of the useful features referenced by Bill Joy in C shell is the command history. This function maintains the history of previously executed commands and allows users to check and easily select previous commands for execution. For example, if you type the command history, the Command previously executed is displayed. You can use the up and down arrows to select commands, or you can use !! Run the previous command. You can also reference the parameters of previous commands, such! * Reference all parameters of the previous command! $ Reference the last parameter of the previous command.
Let's take a look at a simple example of the tcsh script (listing 1 ). This script obtains a parameter (a directory name) and outputs all executable files in the directory and the number of files found. I will reuse this script design in each example to demonstrate the difference.
The tcsh script can be divided into three basic parts. First, note that I use the shebang or hashbang symbol to declare this file as an executable shell file (in this example, a tcsh binary file) that can be defined. This allows me to execute this file in the form of a regular executable file, without adding the interpreter binary file before it. It maintains the number of executable files found, so I initialized the number to 0.
Listing 1. scripts written in tcsh to find all executable files
#! /Bin/tcsh
# Find all executables
Set count = 0
# Test arguments
If ($ # argv! = 1) then
Echo "Usage is $0
"
Exit 1
Endif
# Ensure argument is a directory
If (! -D $1) then
Echo "$1 is not a directory ."
Exit 1
Endif
# Iterate the directory, emit executable files
Foreach filename ($1 /*)
If (-x $ filename) then
Echo $ filename
@ Count = $ count + 1
Endif
End
Echo
Echo "$ count executable files found ."
Exit 0
The first part tests the parameters passed by the user. # The argv variable indicates the number of input parameters (excluding the command name itself ). You can specify the indexes of these parameters to access them. for example, #1 indicates the first parameter (short for argv [1 ). This script requires a parameter. If this parameter is not found, an error message is output. $0 indicates the name of the command entered on the console (argv [0]).
The second part ensures that the input parameter is a directory. If this parameter is a directory, The-d operator returns True. However, please note that I specified one first! Symbol, which indicates invalid. In this way, the expression indicates that if the parameter is not a directory, an error message is output.
The last part iterates the files in the directory to test whether they are executable files. I use a convenient foreach iterator that loops through every item in parentheses (in this example, this directory) and then tests each item in a loop. In this step, use the-x operator to test whether the file is executable. If yes, output the file and add one to the number. At the end of the script, I output the number of executable files.
Korn shell
Designed by David Korn, Korn shell (ksh) was introduced in the same period as Tenex C shell. One of the most interesting features of the Korn shell is that it is not only backward compatible with the original Bourne shell, but can also be used as a scripting language.
In 2000, Korn shell was released in open source form (based on the Common Public License) and has been a dedicated software. In addition to powerful backward compatibility with the Bourne shell, the Korn shell also contains other shell functions (such as the historical functions of csh ). The shell also provides some more advanced features that can be found in modern scripting languages (such as Ruby and Python)-such as associating arrays and floating point algorithms. The Korn shell can be used in a variety of operating systems, including IBM®AIX®And HP-UX, dedicated to supporting Portable Operating System Interface for UNIX (POSIX) shell language standards.
The Korn shell is a derivative of the Bourne shell, so it looks more like the Bourne shell and Bash than the C shell. Let's look at a Korn shell example for finding executable files (listing 2 ).
Listing 2. scripts written with ksh to find all executable files
#! /Usr/bin/ksh
# Find all executables
Count = 0
# Test arguments
If [$ #-ne 1]; then
Echo "Usage is $0
"
Exit 1
Fi
# Ensure argument is a directory
If [! -D "$1"]; then
Echo "$1 is not a directory ."
Exit 1
Fi
# Iterate the directory, emit executable files
For filename in "$1 "/*
Do
If [-x "$ filename"]; then
Echo $ filename
Count = $ (count + 1 ))
Fi
Done
Echo
Echo "$ count executable files found ."
Exit 0
In listing 2, the first point you will notice is its similarity with listing 1. In terms of structure, the script is basically the same, but there are significant differences in execution conditions, expressions, and iteration methods. Without a Test operator similar to C, ksh uses typical Bourne-style operators (-eq,-ne, and-lt ).
The Korn shell also has some differences related to iteration. In the Korn shell, the for in structure is used, and the command replacement is used to represent the list of files created from the standard output of the command ls '$1/* (indicating the content of the specified subdirectory.
In addition to other features defined above, Korn also supports the alias function (used to replace a word with a user-defined string ). Korn has many other features that are disabled by default (such as file name completion), but can be enabled by users.
Bourne-Again Shell
Bourne-Again Shell (or Bash) is an open-source GNU project designed to replace the Bourne shell. Bash, developed by Brian Fox, has become one of the world's most popular shells (in Linux, Darwin, Windows®, Cygwin, Novell, and Haiku ). As the name suggests, Bash is a superset of the Bourne shell, and most of the Bourne scripts can be executed intact.
In addition to supporting script backward compatibility, Bash also integrates features from Korn and C shell. You will find Command History, command line editing, a directory stack (pushd and popd), and many useful environment variables and command completion.
Bash continues to develop with many new features, supporting regular expressions (similar to Perl) and associated arrays. Although some of these functions may not exist in other scripting languages, you can write scripts compatible with other languages. For this purpose, the sample script shown in listing 3 is equivalent to the Korn shell script (from listing 2), except for the shebang difference (/bin/bash ).
Listing 3. scripts written in Bash to find all executable files
#! /Bin/bash
# Find all executables
Count = 0
# Test arguments
If [$ #-ne 1]; then
Echo "Usage is $0
"
Exit 1
Fi
# Ensure argument is a directory
If [! -D "$1"]; then
Echo "$1 is not a directory ."
Exit 1
Fi
# Iterate the directory, emit executable files
For filename in "$1 "/*
Do
If [-x "$ filename"]; then
Echo $ filename
Count = $ (count + 1 ))
Fi
Done
Echo
Echo "$ count executable files found ."
Exit 0
A key difference between these shells is the license for their release. As you may have guessed, Bash was developed in the GNU Project and published based on GPL, csh, tcsh, zsh, ash, and scsh are all released based on BSD or a license similar to BSD. The Korn shell can be used according to the Common Public License.
External shell
A bold developer can use an alternative shell based on your needs or interests. Scheme shell (scsh) provides a script environment that uses Scheme (a derivative of the Lisp language. Pyshell is an attempt to create a script similar to the Python language. Finally, for embedded systems, BusyBox can be used to merge a shell and all commands into a binary file to simplify distribution and management.
Listing 4 shows a script written in Scheme shell (scsh) to find all executable files. This script may seem strange, but it implements a feature similar to the script class we currently provide. This script contains three functions and uses the executable code (at the end) to test the number of parameters. This script is truly powerful in the showfiles function. it iterates a list (constructed after with-cwd) and calls write-ln after each element in the list. This list is generated by iterating the specified directory and filtering out files that are executable files.
Listing 4. scripts written in scsh to find all executable files
#! /Usr/bin/scsh-s
! #
(Define argc
(Length command-line-arguments ))
(Define (write-ln x)
(Display x) (newline ))
(Define (showfiles dir)
(For-each write-ln
(With-cwd dir
(Filter file-executable? (Directory-files "." # t )))))
(If (not (= argc 1 ))
(Write-ln "Usage is fae. scsh dir ")
(Showfiles (argv 1 )))
Conclusion
Many concepts and a large number of interfaces of the early shell have not changed in the next 35 years-this is a strong proof of contributions to the original authors of the early shell. In an industry that is constantly self-transforming, shell has been greatly improved, but has not undergone major changes. Despite some attempts to create a special shell, the derivatives of the Bourne shell are still the main shells used.