The name and concept of the shell evolved from its Unix predecessor, Multics. Applications are invoked and executed by the system through the shell.

The general term sh refers to bsh (Bourne shell), but Bourne shell is not bash. bash is Bourne Again Shell.

Bourne family shells

Thompson shell

The Thompson shell (or V6 shell) was the first Unix shell in history, written by Ken Thompson and added to UNIX in 1971. It was a simple command-line interpreter, but could not be used to run shell scripts. Many of its features influenced the development of later command-line interfaces. After Unix V7, it was replaced by the Bourne shell.

At that time, the only keywords were if and goto.

Pipelines and redirects were made at that time.

1
2
3
4
# 管道
command1 | command2
# 输出重定向
command1 > file1

PWB shell

The PWB shell is an improved version of the Thompson shell and is fully compatible with the Thompson shell.

These two variables were introduced to solve the hard-coding problem: $HOME , $PATH.

Add double quotes to put variables inside "".

1
2
3
4
5
6
VAR=World
echo "Hello $VAR"
# hello world

# 或者使用这样消除歧义的写法
echo "Hello ${VAR}"

PHP is also designed with this in mind.

1
2
3
4
<?php
$VAR="World";
echo "Hello $VAR";
// hello world

Perl is the same way.

1
2
$VAR = "World";
print "Hello $VAR";

This is still the if-then-else-endif syntax.

Bourne shell

The Bourne shell was first publicly released as part of Unix V7 in 1979. (Almost all Unix and Unix-like systems are descendants of Unix V7).

The Bourne shell is not compatible with the Thompson shell. Then the bizarre syntax case ~ in ~ esac was born.

Here Documents was also born at this time with cat <<-EOF.

1
2
3
cat > file1 << EOF
233
EOF

There is also the addition of the command subcommand.

1
2
3
4
5
echo "两数之和为 : `expr 2 + 2`"

echo "Hello `echo World`"

go run `ls *.go | grep -v _test.go`

The Bourne shell replaced the earlier Thompson shell, which occurred early in Unix history and is now almost forgotten. However, why did the Bourne shell replace the Thompson shell?

Ken Thompson did not want to continue to maintain the shell, and another problem was that the Thompson shell was not sufficiently adapted to unix, and the PWB shell had difficulty solving the Thompson shell’s own problems. Or maybe the shell was just an interface for the user. Something as trivial as the web interface we see today. No one probably thought at the time that the shell would become a language or a standard.

Csh

Bill Joy developed the C shell for BSD UNIX (Berkeley Software Distribution UNIX) in 1978 while he was still a student at UC Berkeley.

The C shell’s C is derived from the c language and has a syntax closer to c, but is not compatible with the Bourne shell.

csh has made significant improvements to interactive use.

  • Command History

  • ~ appeared as an alternative to $HOME

  • alias command

    1
    2
    3
    4
    
    alias gc='git commit'
    
    # Overriding aliases
    alias ls='ls -la'
    
  • Recently accessed directory stack

    • dirs show current directory stack dirs -v

    • pushd enters the stack and switches between directories (equivalent to cd && dirs)

      • pushd has the same effect as cd - without arguments
      • pushd and cd have exactly the same arguments cd -1 , cd +2 , cd -0, pushd +0, pushd -2
    • popd comes out of the stack and switches to the directory at the top of the stack

      1
      2
      3
      4
      5
      6
      
      [user@server /etc] $ dirs
      /usr/bin
      [user@server /usr/bin] $ pushd /etc
      /etc /usr/bin
      [user@server /etc] $ popd
      /usr/bin
      
  • Task control

    • Ctrl-z sends the signal SIGTSTP to the current task, which will be hung and put into the background

    • bg put the pending task to continue execution (in the background)

    • fg Put the background task to the foreground and resume execution if it is pending

    • & Put the task to run in the background

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      
      sheep 10
      # Ctrl-z 暂停这个任务
      
      # bg 命令把他放到后台运行
      bg
      
      # 也可以直接放到后台运行
      sleep 10 &
      # fg 把后台最上面的放到前台运行
      fg
      

Tcsh

Five years after the advent of Csh, Ken Greer of Carnegie Mellon University introduced some features of the Tenex system, such as command line editing and automatic filename and command completion. Developed the Tenex C shell (tcsh)

Added to csh

  • line editing
  • command completion

!! Execute the previous command

!n Execute the n previously executed commands

The default shell for Mac OS X as of 10.1 puma is tcsh

tcsh is still maintained today and we can see the code on Github: tcsh-org/tcsh

KornShell

KornShell (ksh) was developed by David Korn at Bell Labs in the early 1980s and released on USENIX on July 14, 1983 (about the same time as the Tenex C Shell).

The original development was based on the Bourne shell source code. Early Bell Labs contributors Mike Veach and Pat Sullivan, who developed the emacs and vi style line editing modes, respectively.

KornShell is backwards compatible with the Bourne Shell and includes many of the features of the C Shell, as requested and inspired by Bell Labs users. The most notable feature is scripting support.

zsh/bash now also has these two line editing modes: the default is the emacs style

  • Ctrl-b move the cursor left
  • Ctrl-f move the cursor right
  • Ctrl-p View previous command (or move cursor up)
  • Ctrl-n View the next command (or move the cursor down)
  • Ctrl-a Move the cursor to the beginning of the line
  • Ctrl-e Move the cursor to the end of the line
  • Ctrl-w Delete the previous word
  • Ctrl-u Delete from the cursor to the beginning of the line
  • Ctrl-k Delete from the cursor to the end of the line
  • Ctrl-y Paste the deleted text (e.g. paste what was deleted by Ctrl-u)
  • Alt-right, Alt-f, Ctrl-right move a word to the right
  • Alt-lift, Alt-b, Ctrl-lift move a word to the left

But in Apple devices, only Alt-right, Alt-lift are available for moving a word

I think the most used ones are Ctrl-a (move to the beginning of the line, with a sudo) and Ctrl-e (move to the end of the line)

You can also use set -o vi to switch to vi style operation, but I personally don’t use this because most of the cases are only one line, and there are too few long commands that need careful editing. The most painful part is that the vi style operation has a mode, and you can’t see the mode status, so you can only type blindly.

There is even support for Associative Array. What’s an associative array? It is common in modern scripting languages (Ruby and Python, etc.) and is also known as a Map or Dictionary. Or a hashmap (technically a hashmap is just an implementation of an associative array).

1
2
3
4
5
6
7
8
declare -A filetypes=([txt]=text [sh]=shell [mk]=makefile)
filetypes[c]="c source file"

# 获取关联数组的长度
echo ${#filetypes[*]}

# 输出键为 txt 的值
echo ${filetypes[txt]}

POSIX shell

The POSIX shell is based on the 1988 version of KornShell (ksh88), which in turn was designed to replace the Bourne shell on AT&T Unix and surpass the BSD C shell in functionality. To the extent that ksh is the ancestor of the POSIX shell, most Unix and Unix-like systems today include some variant of the Korn shell. Unix and Unix-like systems today include some variant of the Korn shell. The exceptions are generally tiny embedded systems that cannot afford the space required for a full POSIX shell.

What we call POSIX shell compatibility today is the standard that was derived at this time.

Ash

The Almquist shell (also known as A shell, ash, and sh) is a lightweight Unix shell (the best feature is its light weight). It was originally written by Kenneth Almquist in the late 1980s. It replaced the Bourne shell in the BSD version of Unix.

There are two important branches outside the BSD world.

  1. dash (the Debian Almquist shell) was implemented as the default /bin/sh by Debian and Ubuntu in 2006. (Bash is still the default interactive command shell in Debian derivatives.)
  2. The ash command in BusyBox, which is often used in embedded Linux, can be used to implement /bin/sh. Since it was released before dash and it is derived from Debian’s old ash package, I choose to consider it a derived form of dash rather than ash, even though it is a command name in BusyBox that is also ash (BusyBox also includes a ash replacement called hush, which is less powerful which is weaker. Usually, only one of these two will be built into a given BusyBox binary: ash by default, but hush when space is very tight. (Thus, BusyBox-based /bin/sh systems are not always like dash.)

Embedded Linux systems, or Linux-based routing systems: BusyBox ash for OpenWRT and the like

Rc shell

rc (Run Commond) is the command line interpreter for Unix V10 and Plan 9 of the Bell Labs operating system. It is similar to the Bourne shell, but its syntax is slightly simpler. Developed by Tom Duff, this is not POSIX shell compatible

Bash (Bourne Again Shell)

Bash (Bourne Again Shell) is a Unix shell and command language written by Brian Fox for the GNU project, and is a freeware replacement for the Bourne Shell. It was first released in 1989 and is used as the default login shell for most Linux distributions.

Bash is also a pun. It also means “Born Again shell”.

Korn Shell was originally proprietary software until 2000, when it was released as open source software (under the General Public License)

BSD Unix avoided it in favor of the C shell, and its source code was not freely available for Linux at the time of its inception. So when early Linux distributions went looking for a shell to go with their Linux kernel, they often chose GNU Bash

Since the release of Mac OS X 10.2 Jaguar in 2002, Mac OS X has also switched to Bash

This early connection between Linux and Bash pretty much sealed the fate of many other shells, including ksh, csh, and tcsh, which are still used by some die-hard fans today.

signal processing (using trap)

1
2
3
4
5
6
7
# 捕获 INT 信号来实现安全的退出
# trap ctrl-c and call ctrl_c()
trap ctrl_c INT
function ctrl_c() {
  echo "** Trapped CTRL-C"
  exit
}

Debug mode is available

  • bash -x script.sh to run the script and also -v to output more detailed information
  • set -x to enable debug mode
  • set +x to disable debug mode

Or you could say: Here String is a variant of Here Document

Bash can redirect standard input (stdin) from here string using the << operator.

1
cat <<< 233

Zsh

Paul Falstad wrote the first version of Zsh in 1990 while he was a student at Princeton University. The name zsh is derived from the name of Zhong Shao, a professor at Yale University. Paul Falstad thought that Shao’s login ID “zsh” was a good name for the shell.

There is also a theory floating around that z is the last letter of the alphabet, and that zsh means the last shell, or as of now, probably the last generation of the POSIX shell.

MacOS X 15 Catalina changed the default shell program to Zsh. In February 2009, Bash 4.0 switched its license to GPLv3. Some users suspect that this license change is the reason MacOS continues to use older versions. With the release of MacOS Catalina in 2019, Apple changed the default shell.

Zsh’s emulation mode emulate sh

Zsh is compatible with Bash. This is both true and false, because Zsh itself, as a scripting language, is not compatible with Bash. A Bash-compliant script is not guaranteed to be executed correctly by the Zsh interpreter. Therefore, the Zsh implementation includes an emulation mode that supports emulation of the two major Bourne-derived shells (bash, ksh) and the C shell (support for csh is not complete).

In Bash emulation mode, you can use the same syntax and set of commands as Bash, for near complete compatibility. To use emulation of Bash, you need to explicitly execute.

1
emulate bash

Default system shell and compatibility

On many systems, the default interactive command shell program and /bin/sh are different things. /bin/sh may be.

  • The original Bourne shell. This is common on older UNIX systems, such as Solaris 10 (released in 2005) and its predecessors.
  • Korn Shell (ksh93), e.g. OpenBSD, Solaris 11 (2010).
  • Various Ash, which was Ash (ash for script execution and Bash for interactive control) for major Linux distributions in previous years. Nowadays, many of them are Bash.
  • GNU Bash, when called sh, disables most of its non-POSIX extensions.

All this history explains why the creators of upstarts like bash, zsh, and yash (yet another shell) chose to make them compatible with sh. Bourne/POSIX compatibility is the minimum that a shell for Unix-like systems must provide in order to gain widespread adoption. This is sh-compatibles.