【问题标题】:How to programmatically extract the Python version in a shell script?如何以编程方式在 shell 脚本中提取 Python 版本?
【发布时间】:2019-10-11 03:28:42
【问题描述】:

python --version 作为终端输入,我想确认(也以shell 编程的形式在shell 中)安装的任何python 版本是否为3 或更高。例如,

Python 3.2.1

会产生True 或某种形式的确认,其中 python2.2p1Python 2.1.4 将产生 False

我尝试通过 sed 或 grep 使用正则表达式,但无法获得。

注意,这与一些人认为的重复是不同的,因为我问的是可以自动确认安装 python3 或更高版本的 shell 编程代码,而不是手动检查它的方法(只需输入python --version)。

【问题讨论】:

  • 不是没有安装Python时的输出吗?
  • 在您的情况下,似乎根本没有安装 python。要捕获这种情况,您应该询问您的包管理员,而不是使用python -V。您使用哪个包管理器?是apt 吗?此外,如果您想使用第 3 版,请致电 python3 而不仅仅是 python
  • 此输出来自 Bash 的 Ubuntu command-not-found 挂钩。据我了解,它甚至不应该在脚本中运行。
  • 这不是骗子,至少不是所选的骗子目标。这里的问题不是如何让 Python 报告其版本(欺骗目标的主题及其所有答案),而是如何编写解释该(可能还有其他)输出的 shell 脚本 .

标签: regex bash awk sed


【解决方案1】:

在终端输入 python --version 作为输入,我想确认(也以 shell 编程的形式在 shell 中)安装的任何 python 版本是否为 3 或更高。

如果python 命令启动任何版本的cpython,那么python --version 的输出(到它的stderr,而不是stdout)将具有以下形式:

Python X.Y.Z

您可以像这样在 shell 脚本中进行测试:

if python --version 2>&1 | grep -q '^Python 3\.'; then
  # It's python 3 ...
else
  # It's not python 3; maybe not installed
fi

请注意,您最初在问题中提供的输出表明根本没有安装 Python。上述方法将在该事件中执行else 分支。另请注意,可以使用不同的名称安装 Python - 例如,在我输入此名称的系统上,python 是 Python 2.7.5,但 Python 3.4.8 可通过命令 @987654327 获得@。您可以扩展上述内容以测试 Python 3 的一些可能的替代名称,但您无法安全、可靠或有效地对 Python 3 是否安装在任何名称或路径下进行详尽的测试。

【讨论】:

  • 重新考虑后,我认为这应该是公认的答案,考虑到要求,我的解决方案设计过度。
【解决方案2】:

在 Bash 中执行此操作的最简单方法是使用 sort -V

为了解决 bash 中一般比较版本字符串的问题,这里有一个简单的compare() 函数,它接受两个参数 a 和 b,如果 a

# test.sh

compare() {
  local a=$1 ; local b=$2
  [ "$( (echo "$a" ; echo "$b") | sort -V | head -1)" == "$a" ]
}

test22p1() {
  compare "2.2p1" "3.0.0"
  assertTrue "$?"
}

test214() {
  compare "2.1.4" "3.0.0"
  assertTrue "$?"
}

test300() {
  compare "3.0.0" "3.0.0"
  assertTrue "$?"
}

test372() {
  compare "3.7.2" "3.0.0"
  assertFalse "$?"
}

. shunit2

输出:

▶ bash test.sh
test22p1
test214
test300
test372

Ran 4 tests.

OK

(那些单元测试当然假设安装了shunit2。)

关于功能:

它只是在两条单独的行上回显$a 然后$b,管道进入sort -V,然后占据头部。如果头部等于左侧,则返回 true ;否则如果等于右边,则返回false。

在您提到的问题中,您确实想知道是否安装了 Python 3 或更高版本,因此您可以对其进行修改并改为:

python3_installed() {
  local a b
  a=$(python --version 2>&1 | perl -pe 's/python *//i') ; b=3
  [ "$( (echo "$a" ; echo "$b") | sort -V | head -1)" == "$b" ]
}

此函数将计算实际安装的 Python 版本,并使用 sort -V 将其与“3”进行比较,并返回 false,除非安装了 3 或更高版本。

注意使用 Perl 进行不区分大小写的正则表达式搜索和替换。 (并非所有 sed 都具有不区分大小写的能力。)

这样做的好处是你可以在调用它时获得可读的代码,例如:

if python3_installed ; then
  # yes it is!
else
  # ...
fi

最后,根据 sort -V 的文档(来自 BSD 手册;POSIX 没有指定 -V 选项,但大多数似乎都有):

`-V, --version-sort`

对版本号进行排序。输入行被视为 PREFIX VERSION SUFFIX 形式的文件名,其中 SUFFIX 匹配正则表达式 (.([A-Za-z~][A-Za-z0-9~]*)?)*。这些文件按其前缀和版本进行比较(版本号中忽略前导零,请参见下面的示例)。如果输入字符串与模式不匹配,则使用字节比较函数对其进行比较。所有字符串比较都在 C 语言环境中执行,语言环境设置被忽略。

【讨论】:

    【解决方案3】:

    这是完成这项工作的示例 awk 脚本:

    echo $(python --version) | awk 'BEGIN{found="false"}/python-3/{found="true"}END{print found}'
    

    【讨论】:

    • 那是useless use of echo。而且它不会透露您拥有哪个版本。
    • echo 用于为 awk 提供标准输出。如果没有 echo 命令,awk 需要输入文件。
    • 不,你完全错了。如果 Python 将版本信息打印到标准输出,管道会将其提供给 Awk 的标准输入,就像来自 echo 一样;如果没有,您的 echo 将毫无帮助。
    • ...但事实并非如此。 python --version 将其输出定向到标准错误,而不是标准输出。此外,当python 是版本3 cpython 时其错误输出与/python3/ 不匹配。
    猜你喜欢
    • 1970-01-01
    • 2010-09-08
    • 1970-01-01
    • 2016-05-19
    • 2010-12-24
    • 1970-01-01
    • 2017-12-03
    • 1970-01-01
    • 2021-08-20
    相关资源
    最近更新 更多