我怎样才能安全地获得 ksh 的版本?

Sil*_*eth 13 ksh version shell-script portability

如何从 ksh 脚本中安全地获取 ksh 版本?

我已经看到以下解决方案:

  1. ksh --version
  2. echo ${.sh.version}
  3. echo $KSH_VERSION

并且在适当的情况下,每一个都可以正常工作。但是,我关心不完美的情况。

具体来说,我使用的几台机器都有旧版本的 ksh,就我而言,这些机器严重缺乏功能。无论如何,我想(以编程方式)检查版本的原因是查看 ksh 版本是否是功能较弱的版本之一;如果是这样,我想用不那么棒的代码执行一个分支。

然而,在有问题的机器上,shell 的无能扩展到检查版本......

  • 如果我尝试ksh --version,它不会打印任何内容并打开ksh!
  • 如果我尝试echo ${.sh.version},ksh则将其视为不能用2> /dev/null.

    $ echo ${.sh.version} 2> /dev/null  
    ksh: ${.sh.version}: bad substitution
    
    Run Code Online (Sandbox Code Playgroud)
  • 当然echo $KSH_VERSION看起来工作正常——我的意思是它不会崩溃——尽管在这些机器上它是空白的。另外,我看到的地方是KSH_VERSION只被设定pdksh。

问题:

  • 如何以ksh编程方式安全地检查版本?出于我的目的,我并不真正关心实际的版本号是什么,只关心它是否是ksh.
  • 是否$KSH_VERSION足够好?我的意思是如果它是空白的,那么ksh一定是过时的版本吗?其他论坛是否正确,即使对于较新版本的ksh.
  • 根本就没有办法检查这个吗?

cuo*_*glm 9

KSH_VERSION在ksh9393t 版本之前没有实现。它将被设置在mksh、pdksh、 中lksh。因此,为了检查 的版本ksh,我们可以尝试以下步骤:

  • 检查KSH_VERSION以检测mksh, pdksh,lksh
  • 如果第一步失败,请尝试在ksh93和之间使用不同的功能ksh88/86(让 David Korn 向我们展示)。

考虑到这些,我会选择:

case "$KSH_VERSION" in
  (*MIRBSD*|*PD*|*LEGACY*) printf '%s\n' "$KSH_VERSION" ;;
  (*) [ -z "$ERRNO" ] && printf '%s\n' "${.sh.version}" || echo ksh88/86 ;;
esac
Run Code Online (Sandbox Code Playgroud)


Gil*_*il' 8

我认为.sh.version自 ATT ksh 93 的第一个版本以来就已经存在。它在 pdksh 或 mksh 中不可用。由于${.sh.version}是 ksh93 以外的其他 shell 中的语法错误,请将其测试包装在子 shell 中并将其保护在eval.

_sh_version=$(eval 'echo "${.sh.version}"' 2>/dev/null) 2>/dev/null
case $_sh_version in
  '') echo "This isn't ATT ksh93";;
  …
esac
Run Code Online (Sandbox Code Playgroud)

KSH_VERSION 开始于公共域 ksh 克隆 (pdksh),并在 2008 年使用 ksh93t 添加到实际的 Korn shell。

与其测试版本号,不如测试让您感到痛苦的特定功能。大多数功能都可以通过在子 shell 中尝试一些构造来测试,看看它是否会触发错误。


jll*_*gre 6

对于“真实”ksh版本(即基于 AT&T),我使用以下命令:

strings /bin/ksh | grep Version | tail -2 
Run Code Online (Sandbox Code Playgroud)

这是我得到的各种输出:

原始ksh:

@(#)Version M-11/16/88i
Run Code Online (Sandbox Code Playgroud)

dtksh;

@(#)Version 12/28/93
Version not defined
Run Code Online (Sandbox Code Playgroud)

现代ksh93:

@(#)$Id: Version AJM 93u+ 2012-08-01 $
Run Code Online (Sandbox Code Playgroud)

对于pdksh/msh ksh克隆和现代 AT&Tksh版本,这里有一些工作:

$ mksh -c 'echo $KSH_VERSION'
@(#)MIRBSD KSH R50 2015/04/19
Run Code Online (Sandbox Code Playgroud)

编辑:

我忽略了您是在询问从脚本内部执行此操作,而不是通过知道经过测试的 ksh 二进制文件的路径。

假设你真的想要使用的版本ksh,而不是它支持的功能,这里是一种只使用strings至少应该在 Linux 和 Solaris 上工作的命令的方法:

echo $(for i in $(find /proc/$$ ! -type d ! -name "pagemap" | 
  grep -v "/path/" | grep -v "/fd/" ) ; do
  strings $i | egrep "([V]ersion|[K]SH_VERSION).*[0-9]" | sort -u
done 2>/dev/null)
Run Code Online (Sandbox Code Playgroud)

请注意,此方法不可靠,因为/proc可能无法安装,并且肯定还有其他弱点。它在其他 Unix 操作系统上未经测试。


Sil*_*eth 2

当我为 编写脚本时ksh,我注意到旧版本的-a.ksh 内置whence命令选项似乎不受支持ksh。在我检查的所有系统上似乎都是如此,其中包括 Solaris、AIX、HP-UX 和 Linux。

所以这里是 ksh 函数的解决方案:

is_modern_ksh() {
  if whence -a whence > /dev/null 2>&1 ; then
    return 0 #success -> true
  fi
  #Else the call to `whence` failed because `-a` is not supported
  return 1 #failure -> false
}
Run Code Online (Sandbox Code Playgroud)

使用方法如下:

if is_modern_ksh ; then
  echo "You're using a MODERN version of ksh. :)"
else
  echo "You're using an OLD version of ksh. :("
fi
Run Code Online (Sandbox Code Playgroud)