Shebang env предпочитает версию python

У меня есть скрипты 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

Так как "python2" не существует на Debian, есть ли способ передать предпочтительное приложение? Может быть, с расширением оболочки? Я не возражаю, если это зависит, например, от '/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.

Я бы предпочел не делать ссылку "python2- > python" на Debian, потому что если я дам script кому-то другому, он не будет запущен. Мне также не хотелось бы, чтобы "python" указывал на python2 на Arch, поскольку он ломается с обновлениями.

Есть ли чистый способ сделать это без написания обертки?

Я понимаю, что подобный вопрос был задан раньше, но я не видел никаких ответов, отвечающих моим граничным условиям:) Условная строка shebang для разных версий Python

--- UPDATE

Я взломал уродливое решение оболочки, которое делает эту работу на данный момент.

#!/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

запускает найденную программу $p с вводом из stdin (-) и аргументов pass ($ *)

$p - $* <<EOF
...
EOF

Ответ 1

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

import sys
print sys.argv

Это сначала запускается как оболочка script. Вы можете поместить почти любой код оболочки между '''' и # '''. Такой код будет выполнен оболочкой. Затем, когда python запускается в файле, python будет игнорировать строки, поскольку они выглядят как тройные кавычки для python.

Оболочка script проверяет, существует ли двоичный путь в пути с помощью which python2 >/dev/null, а затем выполняет его, если это так (со всеми аргументами в нужном месте). Подробнее об этом см. Почему этот фрагмент с помощью shebang #!/Bin/sh и exec python внутри 4 одинарных кавычек работает?

Примечание. Строка начинается с четырех ', и их должно быть пробелом между четвертым ' и началом команды оболочки (which...)

Ответ 2

Что-то вроде этого:

#!/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 >>>
@@

Ответ 3

Я оставлю это здесь для справок в будущем.

Все мои собственные скрипты обычно пишутся для Python 3, поэтому я использую модифицированную версию ответа Aaron McDaid для проверки Python 3 вместо 2:

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

import sys
print sys.argv

Ответ 4

Я только что напечатал

$ which python3

в командной строке и использовал его для поиска линии shebang. Затем я вставляю соответствующая линия shebang.

Я должен сказать, что это развитие - настоящая досада. > : (