Python использование функции оболочки - PullRequest
0 голосов
/ 26 апреля 2020

Я использую Msys2 portable под Win 10, но я думаю, это одинаково хорошо подходит и для многих других Linux / bashes.

Как получить скрипт python при запуске из оболочки подскажите, знаете о его функциях оболочки и соответствующих параметрах?

У меня есть bash оболочка, где я определил функцию оболочки myfun

$ type myfun
myfun is a function
myfun ()
{
    ...
    (this contains a call to a shell script, 
      that is found in a directory which is part of $PATH)
}

, которая может принимать параметры Например, $ myfun d, и у меня есть python скрипт myscript.py, который хорошо работает при запуске из оболочки bash. Теперь я хочу добавить строки в myscript.py для выполнения myfun изнутри, и заставить его работать также (как и раньше)

$ python3 myscript.py



EDIT # 1 : после получения ответа я экспортировал функцию с помощью export -f myfun. Затем я попробовал 6 альтернатив в моем сценарии: (Использование / Не использование bash -c) в сочетании с (subprocess.run, os.system, os.popen).

Я перечисляю здесь, для каждого из 6 комбинаций, строки, добавленные к myscript.py, и результат, полученный при выполнении python3 myscript.py:

  1. Добавлено
import subprocess
subprocess.run(["myfun", "d"])

Получено (аналогично предыдущему)

Traceback (most recent call last):
...
FileNotFoundError: [Errno 2] No such file or directory: 'myfun'
Добавлено
import os
os.system("myfun d")

Получен ожидаемый результат.

Добавлено
import os
stream = os.popen("myfun d")

Получено Нет ошибок, но, видимо, ничего не делает (очень странно, нужно проверить, что происходит дальше).

Добавлено
import subprocess
subprocess.run(["bash", "-c", "myfun", "d"])

Получено: Выполнена функция, но игнорируется аргумент функции.

Добавлено
import os
os.system("bash -c \"myfun d\"")

Получен ожидаемый результат.

Добавлено
import os
stream = os.popen("bash -c \"myfun d\"")

Получено Нет ошибок, но, видимо, ничего не делает (очень странно, нужно проверить, что происходит дальше).



Оригинальный вопрос и статус :

Я попробовал несколько вариантов, все не удалось (подробности см. Ниже). С одной стороны, кажется, что, даже выполняя myscript.py из оболочки bash, он запускает отдельную оболочку sh без знания моих функций оболочки. С другой стороны, если добавить print( os.environ ) к myscript.py, я вижу переменные среды, которые установлены в ~/.bashrc, так что по крайней мере это правильно наследуется сценарием из оболочки.


Я перечисляю здесь строки, добавленные к myscript.py, и вывод, полученный при выполнении python3 myscript.py:
  1. Добавлено
import subprocess
subprocess.run(["myfun", "d"])

Получено

Traceback (most recent call last):
...
FileNotFoundError: [Errno 2] No such file or directory: 'myfun'
Добавлено
import os
os.system("myfun d")

Получено

sh: myfun: command not found
Добавлено
import os
stream = os.popen("myfun d")

Получено

/bin/sh: myfun: command not found

1 Ответ

2 голосов
/ 26 апреля 2020

Среда по умолчанию является частной. Экспортируйте функцию и убедитесь, что bash запущен в системном вызове. myfun - это функция bash, для ее запуска необходимо запустить bash.

$ myfun() { echo 1; }
$ export -f myfun
$ python <<<'import os; os.system("bash -c myfun")'
1
$ python <<<'import subprocess as s; s.run(["bash", "-c", "myfun"])'
1
$ python <<<'import os; os.popen("bash -c \'myfun"); # ... '

Обычно я передаю аргументы внутренним командам bash в качестве аргументов для скрипт и передать правильно процитированное $@ расширение:

$ myfun() { echo "\$#=$#" "\$*=$*"; }
$ export -f myfun
$ python <<<'import os; os.system("bash -c \"myfun \\\"\$@\\\"\" -- d")'
$#=1 $*=d

# or way better use subprocess
$ python <<<'import subprocess as s; s.run(["bash", "-c", "myfun \"$@\"", "--", "d"])'
$#=1 $*=d

# but still can do the more unsafe version
# that will undergo word expansion or you have to properly escape the strings
# (and double-double escape for `os.systems`)
$ python <<<'import subprocess as s; s.run(["bash", "-c", "myfun d"])'
$#=1 $*=d
...