2008-08-15
Using a non-standard shell as your login shell
Suppose that you want to use a non-standard shell as your login shell (for the purposes of this, 'non-standard' means that it's not installed system-wide; you have to compile your own version). Further suppose, for the sake of argument, that the shell you want to use doesn't have a command-line option to tell it to be a login shell.
If your shell did have such a command line option, using it as your
login shell would be simple. Set your system shell to /bin/sh and
then have a .profile that just said something like:
SHELL=$HOME/bin/shell; export SHELL exec $SHELL --login
(This doesn't work on some systems in some circumstances, but that's another entry entirely.)
Without such an option, you need some way to make your non-standard
shell think that it is being run as a login shell by login (and things
that imitate it, like your SSH daemon). As you might guess, there is a
long-standing convention for how login communicates this to the shell:
a login shell has a '-' as the first character of its program name.
(This works because the entire argument list, including the program name (aka 'argument zero'), is entirely up to the program that runs you; it need not have anything to do with your actual file name.)
This really means the first character, which means that you need some
way to make the first character be a '-'. As it happens, most or all
shells just use the bare program name if you run something that is found
in your $PATH. So what you need is two-fold: first, you need a version
of your shell that's called '-shell' (easily gotten with a symlink or
a hardlink), and second, you need to add $HOME/bin to your $PATH so
you can run your shell without an absolute or relative path.
This gives you the magic incantation:
SHELL=$HOME/bin/shell PATH=$HOME/bin:$PATH export SHELL PATH exec -shell
(Then you run into a bash irritation.)
2008-08-14
A bash irritation: the incompatible exec
There are a reasonable number of good things about bash (and the
general GNU program attitude of which it is a standards-bearer). But
every so often it does something that causes me
to grind my teeth. This time around the irritation is what bash has
done to the innocent exec command.
What they've done is simple: they've made exec take options.
The easiest way to explain the problem with this is in illustrated form. So:
sh$ exec -rc
<... program runs ...>
bash$ exec -rc
bash: exec: -r: invalid option
exec: usage: exec [-cl] [-a name] file [redirection ...]
bash$ exec -- -rc
<... program runs ...>sh$ exec -- -rc exec: --: not found
Oops.
Since bash's exec takes options, it must complain about invalid
options. This makes it reject valid programs that happen to start with
a dash, so it needs a way around that, but the way is not compatible
with other Bourne shells because, of course, exec does not take
options so there is no need to support an option to ignore things that
look like options.
(As a bonus irritation bash does this all the time, not just when
invoked as bash. So much for compatibility.)
If you are in this situation, it may be helpful to know that one way
of checking to see if you are in bash is to look for the presence of
a $BASH_VERSINFO environment variable. There are probably better
ways, but this one works well enough for me and I could spot it in the
bash manpage.
(I stubbed my toe on this today because Ubuntu 8.04 changed /bin/sh
from bash to another, more strictly Bourne compatible shell, which
made my previous slapdash workaround stop working so I had to actually
pay attention to this issue.)