As a linux server user we are, probably, always interacting with the computer using a shell
. But what is a shell? In this post we will discuss the following:
- What a shell is.
- How to see available shells.
- How to change your login shell.
- How to see your login shell.
- How to change your current shell.
- How to see your current shell.
If you just want the commands please go to the summary. If you would like the details and conduct some practical experiments please read on.
What is a shell?
According to POSIX, the IEEE standard for operating system interface and environments,
The shell is a command language interpreter.
That means we communicate with the OS (Operating System) using command language, and the shell is, basically, the link between the command and the OS. It interprets the commands.
How this interpreter is implemented and what extra features it has is not addressed by the standard. Because of this felxibility different shells are available, which offer different functions. First which shells do we have available to us.
Different types of shells available
There are already different types of shells available. Let’s see which shells are available to us:
[ahmed@amayem ~]$ chsh -l
/bin/sh
/bin/bash
/sbin/nologin
/bin/tcsh
/bin/csh
chsh
means change shell. The -l
option lists the shells. Let’s take a look at the man
page of chsh
:
[ahmed@amayem ~]$ man chsh
We learn the following
-l, --list-shells
Print the list of shells listed in /etc/shells and exit.
So we can also see the shells by taking a look at that file:
[ahmed@amayem ~]$ cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/bin/tcsh
/bin/csh
It is the same output.
Trying to find my current shell experiment
I have read about a few methods but I’ve also heard that they might not all be reliable. Let’s check them out then do some experiements to see how reliable they are.:
SHELL environment variable
[ahmed@amayem ~]$ printenv | grep SHELL
SHELL=/bin/bash
[ahmed@amayem ~]$ echo $SHELL
/bin/bash
/etc/passwd user
[ahmed@amayem ~]$ grep ahmed /etc/passwd
ahmed:x:500:500::/home/ahmed:/bin/bash
Or even better:
[ahmed@amayem ~]$ grep ahmed /etc/passwd | gawk -F : '{print $7}'
/bin/bash
$0 shell variable
There is an actual shell variable of the shell. This is not the SHELL
environment variable we mentioned earlier, though it may have the same value.
[ahmed@amayem ~]$ echo $0
-bash
$$ and ps trick
Like $0
, $$
is also a shell variable and indicates the pid
of the current process. If we print out that value we will see the pid of the process:
[ahmed@amayem ~]$ echo $$
7615
Now we can check using the ps
command to see what the command for that process is:
[ahmed@amayem ~]$ ps -p $$
PID TTY TIME CMD
7615 pts/1 00:00:00 bash
Changing your shell
This is accomplished using the chsh
command as mentioned earlier. Let’s switch to /bin/sh
[ahmed@amayem ~]$ chsh -s /bin/sh
Changing shell for ahmed.
Password:
Shell changed.
Let’s see if our methods for checking the shell still work:
Accuracy of shell checking methods
SHELL environment variable
[ahmed@amayem ~]$ echo $SHELL
/bin/bash
/etc/passwd user
[ahmed@amayem ~]$ grep $USER /etc/passwd | gawk -F : '{print $7}'
/bin/sh
$0 shell variable
[ahmed@amayem ~]$ echo $0
-bash
$$ and ps trick
[ahmed@amayem ~]$ ps -p $$
PID TTY TIME CMD
7615 pts/1 00:00:00 bash
Discovering Why
It seems that only the /etc/passwd
method has different results. We can conclude one of two things:
- The shell was not actually changed and only the preference was changed.
- The
/etc/passwd
method is the only accurate method for indicating the current shell.
We need to do a bit more digging before we can figure it out.
The prompt gave it away
First thing that seemed weird was that the prompt didn’t change as seen above. It stayed at, [ahmed@amayem ~]$
. Shouldn’t it have changed?
Luckily my ssh
session ended while I was busy with something else and on login I found this
-sh-4.1$
Whoa, it changed. Now when we try our methods we get the following:
-sh-4.1$ echo $0
-sh
-sh-4.1$ ps -p $$
PID TTY TIME CMD
549 pts/0 00:00:00 sh
-sh-4.1$ echo $SHELL
/bin/sh
It’s all saying the same thing now. It seems I misunderstood the chsh
command. Let’s check its man
page.
chsh true function
chsh is used to change your login shell.
The keyword was login shell
. That explains it. Changing the login shell didn’t change the current shell. We only saw the difference when we logged back in. Let’s try changing our current shell.
Changing the current shell
Let’s see if the names of the shells can be used as commands. Let’s try tcsh
and see what we get for our methods:
-sh-4.1$ tcsh
[ahmed@amayem ~]$
The prompt changed. That’s good news. Let’s try our methods again:
SHELL environment variable
[ahmed@amayem ~]$ echo $SHELL
/bin/sh
/etc/passwd user
[ahmed@amayem ~]$ grep $USER /etc/passwd | gawk -F : '{print $7}'
/bin/sh
$0 shell variable
[ahmed@amayem ~]$ echo $0
tcsh
$$ and ps trick
[ahmed@amayem ~]$ ps -p $$
PID TTY TIME CMD
7615 pts/1 00:00:00 tcsh
Accuracy results
This time things are clearer. The $0
and $$
methods are the ones that return the actual current shell. The /etc/passwd
method gives the login shell as we found out earlier. The $SHELL
method also seems to give the login shell, however it didn’t change until we logged in again. What is the SHELL
environment variable anyways? POSIX section 8.3 of the Base definitions volume of the POSIX.1-2008 defines it as follows:
SHELL
This variable shall represent a pathname of the user’s preferred command language interpreter. If this interpreter does not conform to the Shell Command Language in XCU Shell Command Language, utilities may behave differently from those described in POSIX.1-2008.
Apparently chsh
doesn’t change that variable. I guess it figures it out at login.
Summary
What is a shell?
According to POSIX, the IEEE standard for operating system interface and environments,
The shell is a command language interpreter.
To View Available Shells
[ahmed@amayem ~]$ chsh -l
or
[ahmed@amayem ~]$ cat /etc/shells
To Change the Login Shell
[ahmed@amayem ~]$ chsh -s /bin/sh
Changing shell for ahmed.
Password:
Shell changed.
Just change bin/sh
with the shell you want. This will NOT change your current shell. It will only change your login shell by changing the shell entry for your user in /etc/passwd
. It will also not change the SHELL
environment variable which is supposed to show your preferred login shell. So until you login again your SHELL
environment variable will be wrong.
To View your Login Shell
The most trusted way is looking at /etc/passwd
[ahmed@amayem ~]$ grep $USER /etc/passwd | gawk -F : '{print $7}'
/bin/sh
Looking at SHELL too could work, except that it will be wrong if you have used chsh
to change the login shell and haven’t logged back in.
[ahmed@amayem ~]$ echo $SHELL
/bin/sh
To Change the Current Shell
-sh-4.1$ tcsh
[ahmed@amayem ~]$
Simply issue the name of the shell you want as a command, for example, bash
.
To view your current shell
$0 shell variable
[ahmed@amayem ~]$ echo $0
tcsh
Or
$$ and ps trick
[ahmed@amayem ~]$ ps -p $$
PID TTY TIME CMD
7615 pts/1 00:00:00 tcsh
Extras
Posix definitions for $0 and $$ special parameters
While trying to figure things out I took a look at the posix definitions of $$ and $0. Here they are for reference.
$0
As for $0 we learn from section 2.5.2 of The Shell and Utilities volume of POSIX.1-2008,
0
(Zero.) Expands to the name of the shell or shell script. See sh for a detailed description of how this name is derived.
Let’s check sh to find out how the name is derived. We find that the special parameter 0
is mentioned in three places. The following is under options
-c
Read commands from the command_string operand. Set the value of special parameter 0 (see Special Parameters) from the value of the command_name operand and the positional parameters ($1, $2, and so on) in sequence from the remaining argument operands. No commands shall be read from the standard input.
The following is under command_file
under Operands
:
Special parameter 0 (see Special Parameters) shall be set to the value of command_file. If sh is called using a synopsis form that omits command_file, special parameter 0 shall be set to the value of the first argument passed to sh from its parent (for example, argv[0] for a C program), which is normally a pathname used to execute the sh utility.
Finally the following is under command_name
under Operands
:
command_name
A string assigned to special parameter 0 when executing the commands in command_string. If command_name is not specified, special parameter 0 shall be set to the value of the first argument passed to sh from its parent (for example, argv[0] for a C program), which is normally a pathname used to execute the sh utility.
So $0
is the name of the command. When we print $0
straight from the shell it seems to print out the name of the shell.
$$
$
Expands to the decimal process ID of the invoked shell. In a subshell (see Shell Execution Environment ), ‘$’ shall expand to the same value as that of the current shell.
This one is the most reliable as it tells us that even in a subshell it will give the pid of the “current shell”
References
- POSIX, the IEEE standard for operating system interface and environments.
- POSIX environment variable
SHELL
defintion. - Cyberciti for the ways of finding the current shell, and for the
chsh
pointer - Theunixschool for the gawk field separator trick.
- cs.duke.edu for the shell variables.