POSIX-совместимый / cross-shell способ получить версию запущенной оболочки?

One more awk can do the thing

awk -f tst.awk file | column -t | awk -v OFS='\t' '{ print $1,$2,$3,$4 }'
4
25.11.2018, 00:51
2 ответа

К сожалению, текущая версия стандартов POSIX sh не предлагает ни официального флага командной строки, ни переменной среды для надежного доступа к версии оболочки.

К счастью, есть обходные пути. Можно попробовать поставить --versionв оболочку для большинства производных bash (, кроме dash и posh ). Илиecho "$BASH_VERSION"(баш ),echo "$ZSH_VERSION"(зш ),echo "${.sh.version}"(кш ).

Некоторые пакеты различают версии в имени двоичного файла, например, имя приложения командной строки Python v3 python3. Возможно, имя текущего процесса оболочки включает в себя основную версию или двоичный путь оболочки, такой как /bin/sh, ссылается на более конкретный путь, такой как /bin/bash4.4.12. К сожалению, это соглашение не дошло до крошечного сообщества разработчиков оболочки, поэтому вряд ли эти проверки дадут полезные результаты.

Тем не менее, система упаковки может представить номер версии рассматриваемого пакета оболочки. Итак, запуститеdpkg -l <shell>(производные Debian ),yum -l <shell>(производные RHEL ),emerge -Opv <shell>(Gentoo ),pacman -Qi dash(Arch ),brew list dash(Homebrew )и так далее. Если речь идет о оболочке sh, то эта оболочка, скорее всего, предоставляется пакетом coreutils, поэтому запросите у диспетчера пакетов coreutils, а не sh.

Для родственных RVM, cygwin и других Unix-подобных -сред:каталог, содержащий оболочку, может называться версией оболочки. Поэтому возьмите абсолютный путь к приложению оболочки и посмотрите, появляется ли там имя.

Наконец, оболочка может быть просто предоставлена ​​операционной системой, поэтому uname -a; cat /etc/*release*может предоставляться хотя бы какой-то идентификатор для отслеживания версии оболочки.

Если все эти команды соединить точкой с запятой в скрипте, можно было бы получить достаточно всеобъемлющий инструмент грубой силы, похожий на nmap -, для определения версии данной оболочки.

3
27.01.2020, 20:48

Я действительно нашел способ. Модуль тестирования оболочки shunit2 , написанный как сценарии оболочки, имеет «библиотеку версий », в которой также есть код для определения используемой версии оболочки :

.
VERSIONS_SHELLS="ash /bin/bash /bin/dash /bin/ksh /bin/pdksh /bin/sh /bin/zsh"

versions_shellVersion() {
  shell_=$1

  shell_present_=${FALSE}
  case "${shell_}" in
    ash)
      [ -x '/bin/busybox' ] && shell_present_=${TRUE}
      ;;
    *)
      [ -x "${shell_}" ] && shell_present_=${TRUE}
      ;;
  esac
  if [ ${shell_present_} -eq ${FALSE} ]; then
    echo 'not installed'
    return ${FALSE}
  fi

  version_=''
  case ${shell_} in
    */sh)
      # TODO(kward): fix this
      ## this could be one of any number of shells. try until one fits.
      #version_=`versions_shell_bash ${shell_}`
      ## dash cannot be self determined yet
      #[ -z "${version_}" ] && version_=`versions_shell_ksh ${shell_}`
      ## pdksh is covered in versions_shell_ksh()
      #[ -z "${version_}" ] && version_=`versions_shell_zsh ${shell_}`
      ;;
    ash) version_=`versions_shell_ash ${shell_}` ;;
    */bash) version_=`versions_shell_bash ${shell_}` ;;
    */dash)
      # simply assuming Ubuntu Linux until somebody comes up with a better
      # test. the following test will return an empty string if dash is not
      # installed.
      version_=`versions_shell_dash`
      ;;
    */ksh) version_=`versions_shell_ksh ${shell_}` ;;
    */pdksh) version_=`versions_shell_pdksh ${shell_}` ;;
    */zsh) version_=`versions_shell_zsh ${shell_}` ;;
    *) version_='invalid'
  esac

  echo ${version_:-unknown}
  unset shell_ version_
}

# The ash shell is included in BusyBox.
versions_shell_ash() {
  busybox --help |head -1 |sed 's/BusyBox v\([0-9.]*\).*/\1/'
}

versions_shell_bash() {
  $1 --version 2>&1 |grep 'GNU bash' |sed 's/.*version \([^ ]*\).*/\1/'
}

versions_shell_dash() {
  eval dpkg >/dev/null 2>&1
  [ $? -eq 127 ] && return  # return if dpkg not found

  dpkg -l |grep ' dash ' |awk '{print $3}'
}

versions_shell_ksh() {
  versions_shell_=$1

  # try a few different ways to figure out the version
  versions_version_=`${versions_shell_} --version : 2>&1`
  if [ $? -eq 0 ]; then
    versions_version_=`echo "${versions_version_}" \
      |sed 's/.*\([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\).*/\1/'`
  else
    versions_version_=''
  fi

  if [ -z "${versions_version_}" ]; then
    _versions_have_strings
    versions_version_=`strings ${versions_shell_} 2>&1 \
      |grep Version \
      |sed 's/^.*Version \(.*\)$/\1/;s/ s+ \$$//;s/ /-/g'`
  fi

  if [ -z "${versions_version_}" ]; then
    versions_version_=`versions_shell_pdksh ${versions_shell_}`
  fi

  echo ${versions_version_}
  unset versions_shell_ versions_version_
}

versions_shell_pdksh() {
  _versions_have_strings
  strings $1 2>&1 \
  |grep 'PD KSH' \
  |sed -e 's/.*PD KSH \(.*\)/\1/;s/ /-/g'
}

versions_shell_zsh() {
  versions_shell_=$1

  # try a few different ways to figure out the version
  versions_version_=`echo 'echo ${ZSH_VERSION}' |${versions_shell_}`

  if [ -z "${versions_version_}" ]; then
    versions_version_=`${versions_shell_} --version 2>&1 |awk '{print $2}'`
  fi

  echo ${versions_version_}
  unset versions_shell_ versions_version_
}

Это может даже сработать, чтобы получить версию оболочки, когда она не используется, но я признаю, что в моем случае просто использование $BASH_VERSIONили аналогичного может быть более эффективным.

Под лицензией Apache License @kward.

2
27.01.2020, 20:48

Теги

Похожие вопросы