shebang env首选python版本

时间:2013-09-24 22:52:08

标签: python linux scripting shebang

我有一些python-2.x脚本,我在不同的系统,Debian和Arch linux之间复制。 Debian将python安装为'/ usr / bin / python',而Arch将其安装为'/ usr / bin / python2'。 一个问题是,在Arch linux上,'/ usr / bin / python'也存在,它引用了python-3.x. 因此,每次复制文件时,我都必须更正shebang行,这有点烦人。

在Arch上我使用

#!/usr/bin/env python2

在debian上我有

#!/usr/bin/env python

由于Debian上不存在'python2',有没有办法传递首选应用程序?也许有一些shell扩展?我不介意它是否依赖于例如'/ bin / sh'。 以下情况会很好但不起作用。

#!/usr/bin/env python2 python
#!/usr/bin/env python{2,}
#!/bin/sh python{2,}
#!/bin/sh -c python{2,}

令人沮丧的是'sh -c python {2,}'在命令行上运行:即它在可用时调用python2,否则调用python。

我宁愿不在Debian上创建链接'python2-> python',因为如果我将脚本提供给其他人,它将无法运行。我也不想让'python'指向Arch上的python2,因为它打破了更新。

如果没有编写包装器,是否有一种干净的方法可以做到这一点?

我之前已经意识到类似的问题,但我没有看到任何符合我的边界条件的答案:) Conditional shebang line for different versions of Python

---更新

我把一个丑陋的shell解决方案整合在一起,现在可以完成这项工作。

#!/bin/bash
pfound=false; v0=2; v1=6
for p in /{usr/,}bin/python*; do  
  v=($(python -V 2>&1 | cut -c 7- | sed 's/\./ /g'))
  if [[ ${v[0]} -eq $v0 && ${v[1]} -eq $v1 ]]; then pfound=true; break; fi
done
if ! $pfound; then echo "no suitable python version (2.6.x) found."; exit 1; fi
$p - $* <<EOF

PYTHON SCRIPT GOES HERE

EOF

说明: 获取版本号(v是一个bash数组)并检查

v=($(python -V 2>&1 | cut -c 7- | sed 's/\./ /g'))
if [[ ${v[0]} -eq $v0 && ${v[1]} -eq $v1 ]]; then pfound=true; break; fi

使用stdin( - )的输入和传递参数($ *)

启动找到的程序$ p
$p - $* <<EOF
...
EOF

5 个答案:

答案 0 :(得分:19)

#!/bin/sh
''''which python2 >/dev/null 2>&1 && exec python2 "$0" "$@" # '''
''''which python  >/dev/null 2>&1 && exec python  "$0" "$@" # '''
''''exec echo "Error: I can't find python anywhere"         # '''

import sys
print sys.argv

首先作为shell脚本运行。您可以在''''# '''之间放置几乎所有shell代码。这样的代码将由shell执行。然后,当python在文件上运行时,python将忽略这些行,因为它们看起来像是python的三重引号字符串。

shell脚本测试二进制文件是否存在于which python2 >/dev/null的路径中,然后执行它(如果是这样的话)(所有参数都在正确的位置)。有关详情,请参阅Why does this snippet with a shebang #!/bin/sh and exec python inside 4 single quotes work?

注意:该行以四个'开头,并且它们必须在第四个'和shell命令的开头之间没有空格(which ...)

答案 1 :(得分:1)

这样的事情:

#!/usr/bin/env python
import sys
import os
if sys.version_info >= (3, 0):
    os.execvp("python2.7", ["python2.7", __file__])
    os.execvp("python2.6", ["python2.6", __file__])
    os.execvp("python2", ["python2", __file__])
    print ("No sutable version of Python found")
    exit(2)

更新以下是相同版本的更强大版本。

#!/bin/bash

ok=bad
for pyth in python python2.7 python2.6 python2; do
  pypath=$(type -P $pyth)
  if [[ -x $pypath ]] ; then
    ok=$(
      $pyth <<@@

import sys 
if sys.version_info < (3, 0):
  print ("ok")
else:
  print("bad")
@@

    )
    if [[ $ok == ok ]] ; then
      break
    fi
  fi
done

if [[ $ok != ok ]]; then
  echo "Could not find suitable python version"
  exit 2
fi

$pyth <<@@
<<< your python script goes here >>>
@@

答案 2 :(得分:0)

我将此留在这里供将来参考。

我自己的所有脚本通常是为Python 3编写的,所以我使用Aaron McDaid的修改版本来检查Python 3而不是2:

#!/usr/bin/env sh
''''which python3 >/dev/null 2>&1 && exec python3 "$0" "$@" # '''
''''test $(python --version 2>&1 | cut -c 8) -eq 3 && exec python "$0" "$@" # '''
''''exec echo "Python 3 not found." # '''

import sys
print sys.argv

答案 3 :(得分:0)

这是投票率最高的答案的更简洁方法:

#!/bin/sh
''''exec $(which python3 || which python2 || echo python) $0 $@ #'''

import sys
print(sys.argv)
print(sys.version_info)

如果没有找到,您会得到的:

'./test.py: 2: exec: python: not found'

此外,摆脱linter的警告:

'module level import not at top of file - flake8(E402)'

答案 4 :(得分:-2)

我刚输入

$ which python3

在命令行并用它来定位shebang线。然后我插入 适当的shebang线。

我必须说这种发展真的很烦人。 &GT;:(