Разница между подпроцессом Python. Открыть с shell = True и реальной оболочкой - PullRequest
0 голосов
/ 15 мая 2018

Когда я открываю командную строку, я хочу, чтобы она запускалась в том же рабочем каталоге, где находится текущее активное окно.Поэтому я написал скрипт на Python, который определяет правильный путь.В качестве аргумента она принимает команду, открывающую терминал.В этом аргументе он заменяет местозаполнитель на нужный каталог и выполняет команду с

subprocess.Popen(cmd, stderr=subprocess.PIPE, shell=True)

Строка cmd правильно собрана в:

xterm -e 'cd '\''/mnt/data/software/computer/tools/i3'\''; /usr/bin/bash'

Если я выполню эту команду вBash он открывает Xterm в правильном каталоге по желанию.Если я выполню эту команду из сценария Python, xterm не откроет не .

В чем разница?


Дополнительная информация:

IЯ использую Python 3.6.5.

echo $SHELL возвращает /bin/bash.

Связывание клавиш со сценарием в моей конфигурации i3:

bindsym $mod+Return exec "/mnt/data/software/computer/tools/i3/i3_launch_cwd.sh \\"xterm -e 'cd %{cwd}; /usr/bin/bash'\\""

(Этот сценарий оболочкиэто простая оболочка, которая перенаправляет stderr в файл журнала для отладки)

После выполнения следующей команды в bash xterm открывается даже из python:

xrdb -merge -I$HOME ~/.Xresources

Соответствующая строка в Xresources

xterm*faceName: DejaVu Sans Mono Book

Почему это имеет значение?


Решение : Благодаря комментариям Чарльза Даффи я нашел проблему.В моем скрипте python я перенаправляю stderr с stderr=subprocess.PIPE, но я забыл прочитать stderr.Перед загрузкой моего файла Xresources, который устанавливает шрифт, xterm печатает предупреждение для stderr, что шрифт не может быть загружен.У xterm очень маленький буфер.Поскольку моя программа не читает stderr, буфер не очищается, а xterm блокируется.

Замена

subprocess.Popen(cmd, stderr=subprocess.PIPE, shell=True)

на

p = subprocess.Popen(cmd, stderr=subprocess.PIPE, shell=True)
out, err = p.communicate()
sys.stderr.write(err)

Решит проблему.Но поскольку я ничего не делаю с stderr, нет необходимости перенаправлять его в первую очередь.Поэтому вместо этого я сейчас использую

subprocess.Popen(cmd, shell=True)

1 Ответ

0 голосов
/ 15 мая 2018

Не использовать shell=True; это не подходит для вашего случая использования.

import subprocess
try:
    from pipes import quote # Python 2
except ImportError:
    from shlex import quote # Python 3

dir='/mnt/data/software/computer/tools/i3'
p = subprocess.Popen(['xterm', '-e', 'cd %s && exec bash' % quote(dir)])

Однако вы можете упростить это, разрешив subprocess.Popen установить каталог для вас:

dir='/mnt/data/software/computer/tools/i3'
p = subprocess.Popen(['xterm', '-e', 'bash'], cwd=dir)

Тем не менее, shell=True 100% эквивалентно выполнению sh -c '...command...', где буквенный текст вашей команды находится в ...command...; это именно то, что он делает на практике .


Обратите внимание, что я удалил stderr=subprocess.PIPE выше. Вы можете добавить это обратно, но только если ваш код действительно читает содержимое, записанное в stderr, например, путем вызова communicate().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...