It's not surprising that making /bin/sh
a symlink to /bin/zsh
caused problems, since /bin/zsh
often doesn't exist. I suspect zsh
wasn't installed and that's why things broke. This seems especially likely2 if the error you saw on the new terminal was:
bash: /usr/bin/lesspipe: /bin/sh: bad interpreter: No such file or directory
Making /bin/sh
a link to dash
again (as it is by default on Ubuntu) is usually the appropriate solution--and in your case, as your goal is to restore your system to the way it was before, it is definitely the correct way. It can be achieved by booting from live media, as presented in Termhn's excellent answer1, and in other ways.
But if for some bizarre reason you did want to use zsh
instead of dash
for /bin/sh
in Ubuntu, this can be achieved--but not quite the way you attempted it.
Restoring sh
→dash
Without a Live Environment
I think using a live CD/DVD/USB is the overall best solution to this problem, because it's less technical than other ways and is very likely to succeed without problems.
But in case you want to fix this just by booting from the hard disk, you can.
This is somewhat less long and complicated than it might seem at first glance, as a good bit of length is due to (a) presenting two alternatives, and (b) the screenshots.
First, shut down or reboot cleanly (if you can).
This applies to all solutions, not just those that attempt to fix the problem while still booting from the internal hard drive. But it's probably not a big problem if you didn't do this.
Depending on how badly broken things are, Ctrl+Alt+Delete might not successfully shut down and reboot your Ubuntu system. (Ordinarily it does that, if pressed when in a text-based virtual console.)
If Ctrl+Alt+Delete doesn't work, use:
- Alt+SysRq+REISUB to reBoot, or
- Alt+SysRq+REISUO to power Off.
Since problems caused by a missing /bin/sh
shouldn't cause failures deep in the kernel, I think these "magic SysRq" techniques will always work in this situation.
init=/bin/dash
Should Work
Hold down Shift while booting to get a GRUB menu.

It should very generally resemble this screenshot, but may be expected to look different depending on which Ubuntu flavor and release you're running.
"Ubuntu" is selected by default. Keep that selection, but press e to edit it.
(Don't worry, your edit is just for this boot, and will not be saved.)
Move to the end of the line that beginning linux /boot/vmlinuz-...
. (You can use the arrow keys, and End to get to the end of the line.)

Type a space, then init=/bin/dash
. Then press F10 to boot this configuration.
Source: How to set NOMODESET and other kernel boot options in grub2
You should see:
/bin/dash: 0: can't access tty: job control turned off
#
This is a root shell.
Remount the root filesystem readwrite so you can make changes to files on disk:
mount -o remount,rw /
This command, and the ones that follow it, will (usually) not produce any output when they succeed. That's okay.
Make /bin/sh
a symlink to dash
instead of zsh
:
cd /bin
rm sh
ln -s dash sh
If you like, you can check that the sh
symlink has been properly retargeted by running ls -l sh
, which should show something like:
lrwxrwxrwx 1 root root 4 Oct 2 23:13 sh -> dash
(sh -> dash
is the key part.)
Restart with reboot -f
. Your system should be fixed.
Alternative way: Recovery mode might work. Maybe.
It may be possible for recovery mode to function without sh
. I haven't gotten this to work myself and don't actually know if it ever does--I got Ubuntu to boot normally (without a GUI) with sh
as a broken symlink, but that stopped working for me before I tried recovery mode (which didn't work for me either).
For a more reliable way, go back up to init=/bin/dash
Should Work. (Note that recovery mode is not at all unreliable in general, it just can't be expected to work without /bin/sh
.)
If you want to attempt recovery mode:
To enter recovery mode, hold down Shift during boot to get a GRUB menu.
Select Advanced options for Ubuntu.
In the menu of available kernels, press ↓ to move the selection to an entry ending in (recovery mode)
, and press Enter.

If it doesn't work, you can reboot with "magic SysRq" as detailed above. If it does work, you'll see the Recovery Menu.
In the Recovery Menu, press ↓ repeatedly until
root Drop to root shell prompt
is selected. Press Enter.

Perform steps 5 and 6 (and optional step 7, if you like) from the init=/bin/dash
Should Work method above.
Run reboot
to restart.
You could probably run exit
, then select Resume. But I suggest rebooting instead, so the system can boot cleanly with an accessible and functioning sh
from the very start. (If you managed to get into recovery mode with sh
as a broken symlink, that still doesn't mean everything worked just right along the way.)
If you're interested in making zsh
provide sh
(either for real, or just theoretically), read on.
Problems With The sh
→zsh
Procedure You Attempted
As a general procedure, cd /bin; rm sh; ln -s /bin/zsh /bin/sh
(as prescribed in your lab exercise) is bad advice for at least two reasons:
/bin/zsh
sometimes doesn't exist even if zsh
is installed. This depends on how it was installed and what OS is being used. zsh
is a large, complex shell that's not very frequently used as /bin/sh
and thus ordinarily doesn't need to be accessible in single-user mode or otherwise before a separate /usr
partition might be mounted. Executables not needed in single-user mode are usually located in subdirectories of /usr
.
Ubuntu's zsh
does provide /bin/sh
. But on other systems it may be /usr/bin/zsh
or even /usr/local/bin/sh
(as on my FreeBSD system where I have it installed via pkg
).
The motivation behind this exercise may have been to harden a system against "Shellshock" (or other possible parsing bugs arising from the way bash
accepts shell functions passed in environment variables). But it is not a widely appropriate course of action for this purpose.
Although many GNU/Linux systems, such as Fedora, RHEL, and Slackware, have bash
provide /bin/sh
, in many others some other shell provides /bin/sh
. This includes Ubuntu, which uses dash
. Like zsh
, dash
is not vulnerable to "Shellshock" and does not import function definitions from environment variables (or at all) using any mechanism, so no similar bug is likely to affect it.
So depending on context, this exercise as it was presented to you might have been flawed. You might want to discuss the matter with your professor. Perhaps the curriculum, or the way in which it is conveyed, could be improved.
Depending (even more heavily) on context, these considerations may also be causes for concern:
Often, sh
is a symbolic link, hard link, or copy of another shell that is installed. But on some systems, particularly some Unix-like systems that are not GNU/Linux systems, sh
might be a separate executable from anything else. Except when this is known not to be the case, it's a good idea to check before rm
ing it! mv
ing might be more appropriate in that case.
Exercises that alter a system's configuration, particular those that require running commands as root to perform unusual actions, should not typically be performed on production machines. Experimentation and exploration are both practically necessary and intrinsically valuable. But when they may involve breaking things, they are best carried out on installations whose continued functioning is not essential to important work that needs to get done.
In other words, it's good to test things out before deploying them "for real." (Virtual machines are often good for this.)
Ubuntu's zsh
does provide a copy of the shell3 in /bin
as well as /usr/bin
. But by default in Ubuntu, zsh
is not installed at all.
Symbolic links don't require their targets to exist:
ek@Ilex:~$ rm foo
rm: cannot remove ‘foo’: No such file or directory
ek@Ilex:~$ ln -s foo bar
ek@Ilex:~$ ls -l foo bar
ls: cannot access foo: No such file or directory
lrwxrwxrwx 1 ek ek 3 Oct 2 20:25 bar -> foo
ek@Ilex:~$ file bar
bar: broken symbolic link to `foo'
Since /bin/sh
is the interpreter for many important scripts used to boot the system and perform other tasks, it needs to exist. Making it a broken link will render an Ubuntu system non-functioning.
Getting zsh
to Provide /bin/sh
Ubuntu is designed to use dash
for sh
, and is not developed or tested with zsh
as sh
in mind. Please don't attempt this on a system you need for critical tasks. This is strictly for education/fun, and should be done in a non-critical virtual machine or other non-critical system.2
Install zsh
; by default in Ubuntu, it is not installed.
sudo apt-get update
sudo apt-get install zsh
Point sh
at zsh
instead of dash
by running cd /bin; rm sh; ln -s /bin/zsh /bin/sh
(as you did).
Verify sh
is a good link to zsh
by running file sh
(or if you're no longer in /bin
, use file /bin/sh
).
You should see sh: symbolic link to `zsh'
(or /bin/sh: symbolic link to `zsh'
).
Reboot and see if Ubuntu still works.
Notes
- And apparently also, at least sometimes, from a text-based virtual console, also as explained in Termhn's answer. This worked for me one of the times I tested it2, but failed another time I tested it. And I know it did not work for you. (In contrast, the live CD method is very reliable.)
- Testing for this answer was performed on a 64-bit Ubuntu Mate 14.10 Utopic Unicorn (beta) system running in a VirtualBox virtual machine. (Not because there's anything about that configuration that best models this problem, but just because that was the desktop Ubuntu system I had on hand for testing.) That something worked for me does not guarantee it will work for you, even on the same version of Ubuntu.
- On Ubuntu,
/bin/zsh
is usually a symlink to /etc/alternatives/zsh
which is usually a symlink to /bin/zsh5
(which is the actual Z Shell executable). But since both /bin
and /etc
are located on the root filesystem even when /usr
is mounted over a network or otherwise on a separate volume, this is fine.