in reply to Re: The problem of "the" default shell
in thread The problem of "the" default shell

I think you sort of just ignore the whole sysadmin use of Perl [...] portability is a huge issue but not so much when it's a one off script to glue the server together.

Not at all. Imagine you wrote a (shell or perl) script heavily relying on the default shell (/bin/sh) being bash a few years ago, for a Debian 5 (Lenny) or Ubuntu 5 system, or maybe for Ubuntu 6.06 LTS. Running that script on the next newer version of the same(!) distribution suddenly breaks things. Ubuntu 6.10 and debian 6.0 (Squeeze) have switched /bin/sh away from bash and run Debian's variant of the Almquist shell (dash) instead.

No rules were broken, as explained in - dash is still SUSv3 / POSIX compliant, like bash. The problem was that people wrongly assumed /bin/sh == bash, and often still do. If you want bash, explicitly ask for it. Ubuntu explains that in There is a tool called checkbashisms that checks for bash features used in scripts intended to be run by /bin/sh.

[...] because it's fine to rely on bashisms when you are root and know that your shell is bash. [...]

My and your shell and root's shell from /etc/passwd don't matter. system, exec, open, qx, ``, and even system(3) invoke the default shell /bin/sh and not the user's shell.

You may play russian roulette with your system by assuming /bin/sh == bash, but as shown lately by Debian and Ubuntu, that assumption may break sooner or later. It wasn't the first time that /bin/sh was changed, and it won't be the last time. Have a look at various system shells and compare how the default shell of various unix systems (including the *BSDs and MacOS X) changed over time.

Anyway, you can go the painful way of embracing the default shell from perl (by using the single-string variants of system, exec, open, and by using qx/``) instead of avoiding it. You can even get your shell code run by a real bash instead of whatever default shell may be installed. It is quite trivial: stuff everything into a string quoted properly for the default shell, and invoke bash -c $quotedstring.

There's only one catch: You don't always know the exact quoting rules for the default shell, so bash may get arguments you did not want to pass to bash. So, what can you do? Right, use the multi-argument form of system, exec, open to invoke bash:

system('bash','-c','whatever commands shall be executed by bash');

Or, do it the DOS way:

  1. Write a bash script from your perl script to a temporary file, including all arguments that you wanted to pass to the bash, and including output redirection to some more temporary files. Note that you can (and must) use bash quoting rules here. Yes, you successfully avoided guessing the default shell's quoting rules.
  2. Write a temporary file containing input to the bash script, if needed.
  3. Invoke that bash script without arguments using the single-string version of system or open. You can't use exec here, because you have to clean up the temporary files.
  4. Read the output files
  5. Remove the temporary files.

Note that safely creating and removing temporary files, especially as root, is a non-trivial problem of its own that needs its own meditation.

All of this mess just to avoid using the multi-argument forms of system, exec, and open. I won't stop you from doing that. After all, TIMTOWTDI. But I prefer the way of less risk and less work.


Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)