sago
sago

Reputation: 787

How can I find my shell version using a Linux command?

I would like to know about my shell version using a Linux command. I tried the following command, but it shows the type of the shell I am in.

Command:

echo $SHELL

Result:

/bin/bash

Upvotes: 64

Views: 127371

Answers (5)

ale5000
ale5000

Reputation: 727

With these functions you can detect the path, name and version of the current shell.

The code was tested with bash, dash, busybox, mksh, ksh, zsh, bosh, osh, yash and posh. Tested under Windows, Linux, macOS and Android.

The complete file can be found here: https://github.com/micro5k/microg-unofficial-installer/blob/main/tools/bits-info.sh

get_shell_exe()
{
  local _gse_shell_exe _gse_tmp_var

  if _gse_shell_exe="$(readlink 2> /dev/null "/proc/${$}/exe")" && test -n "${_gse_shell_exe}"; then
    # On Linux / Android / Windows (on Windows only some shells support it)
    printf '%s\n' "${_gse_shell_exe}"
    return 0
  elif _gse_tmp_var="$(ps 2> /dev/null -p "${$}" -o 'comm=')" && test -n "${_gse_tmp_var}" && _gse_tmp_var="$(command 2> /dev/null -v "${_gse_tmp_var}")"; then
    # On Linux / macOS
    # shellcheck disable=SC2230 # Ignore: 'which' is non-standard
    case "${_gse_tmp_var}" in *'/'* | *"\\"*) ;; *) _gse_tmp_var="$(which 2> /dev/null "${_gse_tmp_var}")" || return 3 ;; esac # We may not get the full path with "command -v" on osh
  elif _gse_tmp_var="${BASH:-${SHELL-}}" && test -n "${_gse_tmp_var}"; then
    if test "${_gse_tmp_var}" = '/bin/sh' && test "$(uname 2> /dev/null || :)" = 'Windows_NT'; then _gse_tmp_var="$(command 2> /dev/null -v 'busybox')" || return 2; fi
    if test ! -e "${_gse_tmp_var}" && test -e "${_gse_tmp_var}.exe"; then _gse_tmp_var="${_gse_tmp_var}.exe"; fi # Special fix for broken versions of Bash under Windows
  else
    return 1
  fi

  _gse_shell_exe="$(readlink 2> /dev/null -f "${_gse_tmp_var}" || realpath 2> /dev/null "${_gse_tmp_var}")" || _gse_shell_exe="${_gse_tmp_var}"
  printf '%s\n' "${_gse_shell_exe}"
  return 0
}

get_shell_info()
{
  local _shell_use_ver_opt _shell_exe _shell_name _shell_version _shell_is_ksh _tmp_var

  _shell_use_ver_opt='false'
  _shell_exe="${1-}"
  _shell_name=''
  _shell_version=''
  _shell_is_ksh='false'

  if test -n "${_shell_exe}"; then
    _shell_name="$(basename "${_shell_exe}" | tr -d ' ')" || _shell_name=''
    _shell_name="${_shell_name%'.exe'}" # For shells under Windows
  fi

  if test -z "${_shell_name}"; then
    printf '%s\n' 'not-found unknown'
    return 1
  fi

  case "${_shell_exe}" in
    *'/bosh/'*'/sh') _shell_name='bosh' ;;
    *'/oils-for-unix' | *'/oil.ovm') _shell_name='osh' ;;
    *) ;;
  esac

  case "${_shell_name}" in
    *'ksh'*) _shell_is_ksh='true' ;;
    'zsh' | 'bosh' | 'osh' | 'yash' | 'tcsh' | 'fish') _shell_use_ver_opt='true' ;;
    *) ;;
  esac

  # Various shells doesn't support '--version' and in addition some bugged versions of BusyBox open
  # an interactive shell when the '--version' option is used, so use it only when really needed.

  if test "${_shell_use_ver_opt}" = 'true' && _shell_version="$("${_shell_exe}" 2>&1 --version)" && test -n "${_shell_version}"; then
    :
  else
    # NOTE: "sh --help" of BusyBox may return failure but still print the correct output although it may be printed to STDERR
    _shell_version="$("${_shell_exe}" 2> /dev/null -Wversion || "${_shell_exe}" 2>&1 --help || :)"
  fi
  _shell_version="$(printf '%s\n' "${_shell_version}" | head -n 1)" || return "${?}"

  case "${_shell_version}" in
    '' | *'Usage'* | *'invalid option'* | *'unrecognized option'* | *[Uu]'nknown option'* | *[Ii]'llegal option'* | *'not an option'* | *'bad option'* | *'command not found'* | *'No such file or directory'*)
      if test "${_shell_is_ksh}" = 'true' && test -n "${KSH_VERSION-}" && _shell_version="${KSH_VERSION}"; then
        : # For ksh (include also variants like mksh)
      elif test "${_shell_name}" = 'dash' && test -n "${DASH_VERSION-}" && _shell_version="${DASH_VERSION}"; then
        : # For dash (possibly supported in the future)
      elif test "${_shell_name}" = 'dash' && command 1> /dev/null 2>&1 -v 'dpkg' && _shell_version="$(dpkg -s 'dash' | grep -m 1 -F -e 'Version:' | cut -d ':' -f '2-' -s)" && test -n "${_shell_version}"; then
        : # For dash under Linux
      elif test "${_shell_name}" = 'dash' && command 1> /dev/null 2>&1 -v 'brew' && _shell_version="$(NO_COLOR=1 brew 2> /dev/null info 'dash' | head -n 1 | grep -m 1 -F -e 'dash:' | cut -d ':' -f '2-' -s | cut -d ',' -f '1')" && test -n "${_shell_version}"; then
        : # For dash under macOS
        _shell_version="${_shell_version# }"
        _shell_version="${_shell_version#stable }"
      elif test "${_shell_name}" = 'dash' && command 1> /dev/null 2>&1 -v 'apt-cache' && _shell_version="$(apt-cache policy 'dash' | grep -m 1 -F -e 'Installed:' | cut -d ':' -f '2-' -s)" && test -n "${_shell_version}"; then
        : # For dash under Linux (it is slow)
      elif test "${_shell_name}" = 'posh' && test -n "${POSH_VERSION-}" && _shell_version="${POSH_VERSION}"; then
        : # For posh
      elif _shell_version="$(\eval 2> /dev/null ' \echo "${.sh.version-}" ' || :)" && test -n "${_shell_version}"; then
        : # Fallback for old ksh and bosh
      elif test -n "${version-}" && _shell_version="${version}"; then
        : # Fallback for tcsh and fish (NOTE: although this variable would show the version unfortunately the code cannot be run on tcsh and fish due to syntax difference)
      else
        _shell_version=''
      fi
      ;;
    *) ;;
  esac

  case "${_shell_version}" in
    'BusyBox '*) _shell_name='busybox' ;;
    *' bash,'*) _shell_name='bash' ;; # Sometimes "sh" isn't just a symlink to "bash" but it is really called "sh" so we have to correct this
    *) ;;
  esac

  _shell_version="${_shell_version#*[Vv]ersion }"
  case "${_shell_name}" in
    'busybox') _shell_version="${_shell_version#BusyBox}" ;;
    'osh') _shell_version="$(printf '%s\n' "${_shell_version#Oils}" | cut -f '1')" ;;
    'mksh') _shell_version="${_shell_version#*MIRBSD KSH}" ;;
    '') ;;
    *) _shell_version="${_shell_version#"${_shell_name}"}" ;;
  esac
  _shell_version="${_shell_version# }"
  _shell_version="${_shell_version#v}"

  printf '%s %s\n' "${_shell_name:-unknown}" "${_shell_version:-unknown}"
}

shell_exe="$(get_shell_exe)"
echo "${shell_exe}"
get_shell_info "${shell_exe}"

Upvotes: 0

gaurav cmd
gaurav cmd

Reputation: 19

Just use command

echo $BASH_VERSION

It must give you the version of shell. BASH_VERSION is the environment variable which contains version of shell.

Upvotes: 0

Alexander Samoylov
Alexander Samoylov

Reputation: 2558

There is a case when your shell does not have a command line parameter to determine the version directly. This case is Bourne shell. For Bourne shell I would recommend to use a script: https://www.in-ulm.de/~mascheck/various/whatshell/whatshell.sh. The script is pretty small so that it is not a big trouble to review it and understand how it is working. I have tested this script inside different shells on Linux and Solaris and it always gave the shell version for me.

Some examples:

Ubuntu 18.04

$ sh -c './whatshell.sh'
ash (Busybox 1.x)
$ bash -c './whatshell.sh'
bash 4.4.19(1)-release

CentOS 4

$sh -c './whatshell.sh'
bash 3.00.15(1)-release

Solaris 10

~> sh -c './whatshell.sh'
ksh88 Version (..-)11/16/88i (posix octal base)
~> bash -c './whatshell.sh'
bash 4.1.7(3)-release
~> csh -c './whatshell.sh' 
SVR4 Bourne shell (SunOS 5 variant)

AIX 6.1

~> sh -c './whatshell.sh'
ksh88 Version (..-)11/16/88f
~> bash -c './whatshell.sh'
bash 4.2.0(1)-release

This is also answers for the question Bourne shell version which was marked as off topic.

Upvotes: 10

Keith Thompson
Keith Thompson

Reputation: 263257

It depends on whether you want to know the version of your default login shell, or the version of the shell you're currently running. They're not necessarily the same.

For your default login shell, as the accepted answer says, $SHELL --version is likely to work. Most (but not all) shells accept a --version option. (dash does not.) And this assumes that the value of $SHELL hasn't been changed (there can be valid reasons to do so).

For the shell you're currently running, if it happens to be bash you can type:

echo $BASH_VERSION

For tcsh:

echo $version

For zsh:

echo $ZSH_VERSION
echo $ZSH_PATCHLEVEL # shows more detailed information

For ksh:

echo $KSH_VERSION

For fish:

echo $version

Again, this assumes that the relevant variable hasn't been modified (there's rarely any non-malicious reason to change it).

Bash in particular has an array variable $BASH_VERSINFO that gives more information in a form that's easier to process programmatically. Printing $BASH_VERSINFO only prints the first element; to print all elements:

echo "${BASH_VERSINFO[@]}"

Upvotes: 23

This will do it:

$SHELL --version

In my case, the output is:

zsh 5.0.2 (x86_64-pc-linux-gnu)

Upvotes: 71

Related Questions