shell

Shell: shell are cmd language interpreter for GNU OS (or Linux OS). Shell is simply a program that executes cmds. It is used both as cmd interpreter and a pgm language (by allowing multiple cmds to be combined and having them execute based on conditions). Shells can be used interactively (by accepting i/p typed from keyboard), or non-interactively (via script)

2 most common shells are csh and bash. Bash is the default shell in most Linux distros, and is the preferred one. Most of the scripts written for GNU are written in bash, and not csh.

shell basics:

If you power on a computer with no monitor, keyboard and mouse attached, the processor will run the pgm stored in memory, and keep on doing whatever the pgm is asking it to do. This pgm stored in memroy is called the kernel, and is loaded in memeory from bootup time to shut down. If we connect a monitor, the computer will display what the pgm is sending to monitor interface. If we want to make computer useful, we need a hook, so that we can use it to run our pgm. That is possible if we provide a user interface as "mouse/keyboard", but there has to be a program on computer that takes these inputs, and pass it on to some other program that can decide what to do with these user inputs. Shell is one such program, that takes user inputs which is usually a cmd followed by args. Shell passes these details to the kernel, which runs the program, and then passes the o/p to the shell, which then displays the o/p to the user. NOTE: the shell remains in memory, just like kernel which remains in memory all the time. Any cmd (i.e program) that we call from inside shell usually resides on disk, so a copy of that program is loaded in memory and run.

Any shell (bash, csh, etc) is basically a pgm to run other programs. It reads a line of input from you, and then interprets it as one or more commands (i.e programs) to run. Shell pgm is no different than any other pgm.

Shell basic operation on being provded a cmd is to:

  • Read i/p from terminal, or file.
  • Then break this into words and operators. These are called tokens. These tokens are separated by metacharacters (characters with special meaning, as whitespace, newline, $, ;, etc).
  • Then parse the tokens into cmds, and perform various shell expansion i.e parameter expansion, wildcard expansion, etc (redirection is performed if necessary). pattern matching for filenames is done after various shell expansion, and then quote removal (for unnecessary quotes) and finally redirection done just before executing the cmd
  • the cmd never sees any special char in it's args, they are gobbled up the shell. It only sees the cmd and full expanded args, w/o any metacharacters. For pattern matching, glob, etc, see section on
    • ex: ls -l *.c. => shell scans this line, identifies 1st token as pgm "ls", 2nd and 3rd token as 2 args. However, 3rd arg has *, which is expanded by the shell (for ex as tmp1.c and tmp2.c). Now the 3 args: -l, tmp1.c and tmp2.c are passed to the "ls" pgm, which never sees any of these meta char.
    • In case shell can't find anything matching after glob expansion, it passes the whole thing unexpanded to the pgm. So, if *.c doesn't match any file. the whole cmd "ls -l *.c" is passed, so ls pgm sees 2 args: -l and *.c. Now it's upon ls to expand *.c, and if it sees nothing matching, it returns "ls: no match".
    • So, the same utility may behave differently in different dir depending on whether it's capable of handling glob wildcards or not.
    • IMP: To prevent this confusing behaviour, we sometimes prefer to enclose these glob special characters within single or double quotes to prevent the shell from seeing these special characters, and instead pass it as literals to the linux pgm. i.e ls -l "*.c" will prevent shell from expanding *.c as it's surrounded within double quotes, which prevents bash shell from expanding it. For more details, see "bash" or "csh" section on how to escape metacharacters. These quoting mechanism are for shell's use and NOT for linux pgm's use => the pgm sees cmd with these quotes stripped out.
    • Since this all may seem confusing, the best way to know all these nuances is to try linux cmds on shell with/without quotes etc, and chck for yourself how they behave. They may behave differently on different machines depending on what incarnation of linux cmds you have. That's why it's best to stick to "GNU" linux cmds.
  • Now the shell asks the kernel to initiate pgm's execution. In this case, ls pgm execution starts with the 3 args provided. Then shell goes to sleep until the pgm has finished.
  • The kernel copies the specified program into memory and begins its execution. This copied program is called a process; in this way, the distinction is made between a program that is kept in a file on the disk and a process that is in memory doing things. If the program writes output to standard output, it will appear at your terminal unless redirected or piped into another command. Similarly, if the program reads input from standard input, it will wait for you to type in input unless redirected from a file or piped from another command. When the command finishes execution, control once again returns to the shell.

  • shell collects exit status of pgm (which is 1 byte, so exit status is from 0-255. exit status of 0 is true, while other exit status indicate error). This is unique since usually 1 is associated with success, and 0 with failure. But in shells, we keep 0 for success, so that we can assign all other values for failure. NOTE: even though we use 0 for true, when used in conditions, expr, etc, we treat 0 as true, and 1..255 as false. i.e (cmd1 & cmd2) will retrun true(0), when both cmd1 and cmd2 returns true(0). If cmd2 returns 1(false), then this expr will return false (as true & false gives false). NOTE: cmd is executed only after all the expansion has been done by the shell. cmd is always passed the final expanded form.
  • At this point, execution of that pgm is finished, and shell awaits for next cmd. On providing next cmd, cycle starts from top bullet above. This cycle keeps on repeating.

Terminal settings: Before we go into details of various shells, let's see how to change settings in Terminal, Konsole, xterm, etc from where we access the shell. In old days when there was no gui, the first prompt that came up was a shell, from where we typed any cmd.

#to change defaults in konsole gui
Goto settings->size->custom, change cols to 120, lines to 40, save it, then goto settings->save as default. That saves anything changed as default so that next time it starts with those. can also use settings->configure Konsole

#to change defaults in terminal gui

Goto Edit->Profiles->Edit(after choosing default profile) and change any setting. It takes effect immediately

Ex: To change scrolling limit to unlimited, goto "scrolling" tab, and then set Scrollback to unlimited. However, unlimited scollback uses a lot of memory, since it requires a lot of scrollback text to be stored in the buffer, so your computer may slow down a lot, or worse may just hang or crash. A decent compromise is to set scrollback to 500 lines or so.

displaying shells:

To get current shell name in an xterm or terminal: echo $SHELL => shows the current shell (bash or csh). Note that even though it may say csh, it's actually tcsh.

alternative way to print shell: ps -p $$ => ps prints snapshot of current processes (ps -ef shows every process on system, -e=all process, -f=long format, -F=full long format). ps -p prints only those process with that pid number. $ returns the PID of current process (which is the shell), so running ps -p on that number (echo $$ returns PID of current process) displays process status of your shell.

Usually "$" prompt is shown for bash, while "%" prompt is shown for csh.

changing shells:

To change startup shell:
/etc/shells has the list of valid shells. This list updates each time you install a new shell. We can also manually modify this file to add the name of a shell (with full path) if it doesn't show up here after installation.

cat /etc/shells

/bin/sh => This is a soft link to bash in /bin/bash. So, even when we use sh, we are actually using bash

/bin/bash

/usr/bin/sh => This is again a soft link to bash in /usr/bin/bash

/usr/bin/bash => There is a copy of bash in /usr/bin too which is exactly same size as /bin/bash

 Usually we'll see bash already installed. Some Linux distros have tcsh installed too. If above file doesn't show the name of shell that we want, we have to install it by typing below cmds.

sudo apt install tcsh => on debian based distro

sudo yum install tclsh => on fedora based distro


To change shell temporarily, just type the new shell name (i.e bash).
To change user login shell permanently, either edit /etc/passwd file (Administrator's right, this file shows all user's default shell type ), or use change shell cmd (chsh). finger on that user shows default login shell.
chsh -s {shell-name with full path} {user-name} , it will ask for user's password
ex: chsh -s /bin/bash johnsk => changes user johnsk shell from csh to bash

/etc/default/useradd file has settings to be applied anytime a new user is created. We can change SHELL= to whatever we want, and then any new user will get this shell type by default.

NOTE: usually on systems where you don't have admin rights, you can't do chsh. So, if you work at corporation, you can change login shell by going to an internal website, which allows you to choose shell. This is done for security purpose.
for bash, type: /bin/bash, for csh, type: /usr/bin/csh

Common shell:

Customizing prompt for diferent shells: Link: http://understudy.net/custom.html

We'll look at 2 most popular shells: bourne shell (bash), and C shell (csh). Most of the Unix cmds can be used in both shells. But we write larger scripting pgms in a file which is either in bash or csh files. They both support constructs like if-else, loops, etc that allow us to write complicated code. However, these scripting languages were written in early days of Unix. In today's age, modern scriting languages like perl, python, etc can do everything that these bash/csh scripts used to do. So, there is really no reason to learn these scripting languages as bash or csh. I'm providing sections on these 2 scripting languages since you may have to read code written in bash/csh, and possibly modify it, as most of the Linux community uses one or both of these.

For my purpose, learning Python will suffice for all your scripting needs, just bypass both bash and csh.