3

How can I output that what shell is used to execute a script?

Ex.: the $SHELL variable gives that what is the default shell for the given user. That is ok, but the given user can launch the script with other shell, ex.: "sh script.sh" or "csh script.sh".

Using a Linux machine.

  • Rare is the script that can work with both sh and csh. – JdeBP Mar 13 '19 at 18:25
  • Those shells were just examples. The question is that how to know, with what shell is the script actually used in reality. – cirka547 Mar 13 '19 at 18:33
  • 2
    I don't see why this should even be a problem. Don't you use a #!-line in the script? This is never an issue with e.g. Perl, Python or Ruby scripts, so it shouldn't be an issue for a script written for some other interpreter. – Kusalananda Mar 13 '19 at 18:54

2 Answers2

1

Since you specified Linux, this is doable with readlink -f /proc/$$/exe. That will give you (on standard output) the path the the shell executing your shell script (something like /bin/bash). So you could assign it to a variable (at least in POSIX shell) with var=$(readlink -f /proc/$$/exe).

$$ is the pid of the current shell; /proc/«pid»/exe is a kernel feature that lets you query the executable being run in a given pid, in the form of a somewhat "magical" symlink. So you can use readlink to get the path.

On non-Linux, you should be able to use ps, e.g., ps -o args= $$ but that may wind up giving you the script name instead (POSIX allows either behavior).

Except if your script is designed to be sourced to, e.g., set variables in the user's shell, you really ought to use a #! line up top instead to specify which shell to run it under.

derobert
  • 109,670
0

An individual script should not have to test what interpreter it's running in. That kind of introspection is awkward and error prone and would possibly have to be implemented differently for different Unices.

For example, a Perl script can always safely assume that it's being interpreted by a Perl interpreter, a Python script is always run by a Python interpreter, and so on. So why should not a bash script assume that it's being run by bash, and an sh script that it's being run by /bin/sh?

Testing specific capabilities of the current interpreter is a different issue, and e.g. bash offers $BASH_VERSION and the $BASH_VERSINFO array to test a version against (for example).

So how can you make e.g. a bash script be run by bash and a csh script be run by csh? Well, you avoid letting the user pick the interpreter.

You can do that by

  • Not putting a filename suffix on the script file, in case that would "confuse" the user. A bash script in a myscript.sh file might make the user think it would be runnable with sh. Instead, just call the script myscript, and ...

  • Use a #! ("shebang" or "hashbang") line.

A #!-line goes on the very first line of the script (the two characters #! have to be the first in the file) and specifies the path to the interpreter to use.

A bash script may have

#!/bin/bash

if that's the path to the bash executable on your system, or if you want bash to be picked up from wherever in $PATH it's located on your system it could have,

#!/usr/bin/env bash

as its first line, for example.

This ensures that it will always be interpreted by bash and not by sh or csh or python or some other unrelated language interpreter.

The next step would be to

  • Make the script executable, using chmod +x myscript.

Now you can run your script with

./myscript

without bothering with what interpreter to use for executing it. In fact, to the user of the script, it would not matter at all whether it was a bash script, a Python script, or a compiled binary.

Kusalananda
  • 333,661
  • 1
    There is one case you can't use a #! line: when your script is supposed to be sourced into the user's active shell (e.g., to set variables, aliases, or functions) – derobert Mar 13 '19 at 19:40
  • @derobert I would argue that trying to source a bash dot-script in a sh script would be the same kind of user error as trying to load a Python module in Perl. You just wouldn't do that. In any case, you wouldn't try to detect that inside some polyglot script. – Kusalananda Mar 13 '19 at 19:42
  • 1
    It'd be pretty reasonable, for example, to have one script used for all POSIX-sh compatible (enough) shells, and then only enable additional functionality when detecting bash, zsh, etc. That'd make for an easier user (and documentation) experience than a separate script depending on which shell your users happen to be using. And indeed sometimes it's actually required — e.g., in /etc/profile. – derobert Mar 13 '19 at 19:49
  • @derobert I do agree that /etc/profile may be an exception, if you need to differentiate between e.g. dash, bash and ksh (zsh uses another file, and yash does not read files under /etc by default at all). – Kusalananda Mar 13 '19 at 19:56