На моей локальной машине я запускаю скрипт python, который содержит эту строку
bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
os.system(bashCommand)
Это отлично работает.
Затем я запускаю тот же код на сервере и получаю следующее сообщение об ошибке
'import site' failed; use -v for traceback
Traceback (most recent call last):
File "/usr/bin/cwm", line 48, in <module>
from swap import diag
ImportError: No module named swap
Итак, что я сделал, это вставил, print bashCommand
который печатает меня, чем команда в терминале, прежде чем он запускает его os.system()
.
Конечно, я снова получаю ошибку (вызванную os.system(bashCommand)
), но перед этой ошибкой она печатает команду в терминале. Затем я просто скопировал этот вывод и сделал копию вставки в терминал и нажал Enter, и это работает ...
Кто-нибудь знает, что происходит?
cwm
. Может быть, у вас есть какая-то конфигурация,.bashrc
которая настраивает среду для интерактивного использования bash?cwm
. Или, может быть, есть разница в PATH, иcwm
называются разные версии . Или разные версии Python. Это действительно трудно понять без доступа к машине ...Ответы:
Не используйте
os.system
. Это устарело в пользу подпроцесса . Из документации : «Этот модуль намерен заменить несколько старых модулей и функций:os.system
,os.spawn
».Как в вашем случае:
источник
cd 'path\to\somewhere'
другую команду bash, которую нужно было где-то запустить. @ user225312cwd
аргумент для Popen:subprocess.Popen(..., cwd='path\to\somewhere')
stdout=file
в этом случае перенаправляет вывод в файл. Он реализует> file
). Было бы неправильно передавать..., '>', 'file']
последнюю команду, ожидающую перенаправление (она не будет работать без оболочки, и если вы используете оболочку, вы должны передать команду в виде строки)Чтобы немного расширить предыдущие ответы, есть ряд деталей, которые обычно упускаются из виду.
subprocess.run()
болееsubprocess.check_call()
и друзьями в течениеsubprocess.call()
более чемsubprocess.Popen()
надos.system()
болееos.popen()
text=True
, иначеuniversal_newlines=True
.shell=True
или то,shell=False
как оно меняет цитирование, и доступность удобства оболочки.sh
Bash иЭти темы рассматриваются более подробно ниже.
Предпочитаю
subprocess.run()
илиsubprocess.check_call()
Эта
subprocess.Popen()
функция - рабочая лошадка низкого уровня, но ее сложно использовать правильно, и в итоге вы копируете / вставляете несколько строк кода ... которые обычно уже существуют в стандартной библиотеке как набор высокоуровневых функций-оболочек для различных целей, которые представлены более подробно в следующем.Вот параграф из документации :
К сожалению, доступность этих функций-оболочек отличается в разных версиях Python.
subprocess.run()
был официально представлен в Python 3.5. Он предназначен для замены всего следующего.subprocess.check_output()
был введен в Python 2.7 / 3.1. Это в основном эквивалентноsubprocess.run(..., check=True, stdout=subprocess.PIPE).stdout
subprocess.check_call()
был введен в Python 2.5. Это в основном эквивалентноsubprocess.run(..., check=True)
subprocess.call()
был введен в Python 2.4 в исходномsubprocess
модуле ( PEP-324 ). Это в основном эквивалентноsubprocess.run(...).returncode
API высокого уровня против
subprocess.Popen()
Реорганизованный и расширенный вариант
subprocess.run()
более логичен и более универсален, чем старые устаревшие функции, которые он заменяет. Он возвращаетCompletedProcess
объект, который имеет различные методы, которые позволяют вам получить состояние завершения, стандартный вывод и несколько других результатов и индикаторов состояния из готового подпроцесса.subprocess.run()
это путь, если вам просто нужна программа для запуска и возврата управления в Python. Для более сложных сценариев (фоновые процессы, возможно, с интерактивным вводом-выводом с родительской программой Python) вам все равно нужноsubprocess.Popen()
самим позаботиться обо всем подключении. Это требует довольно сложного понимания всех движущихся частей и не должно быть предпринято легко. Более простойPopen
объект представляет (возможно, все еще работающий) процесс, которым нужно управлять из вашего кода в течение оставшейся части времени жизни подпроцесса.Возможно, следует подчеркнуть, что
subprocess.Popen()
просто создает процесс. Если вы оставите все как есть, у вас будет подпроцесс, работающий одновременно с Python, так что это «фоновый» процесс. Если ему не нужно делать ввод или вывод или иным образом координировать с вами, он может выполнять полезную работу параллельно с вашей программой на Python.Избегайте
os.system()
иos.popen()
Со времени вечной (ну, так как Python 2.5)
os
документации модуль содержал рекомендацию предпочитатьsubprocess
болееos.system()
:Проблемы в том
system()
, что он явно зависит от системы и не предлагает способов взаимодействия с подпроцессом. Он просто работает со стандартным выводом и стандартной ошибкой вне досягаемости Python. Единственная информация, которую Python получает обратно, - это состояние выхода команды (ноль означает успех, хотя значение ненулевых значений также в некоторой степени зависит от системы).PEP-324 (о котором уже упоминалось выше) содержит более подробное обоснование причин проблем
os.system
и способовsubprocess
их решения.os.popen()
Раньше был еще более обескуражен :Однако с тех пор в Python 3 он был переопределен для простого использования
subprocess
и перенаправляет вsubprocess.Popen()
документацию для деталей.Понять и обычно использовать
check=True
Вы также заметите, что
subprocess.call()
имеет много тех же ограничений, что иos.system()
. При регулярном использовании вы должны обычно проверять, завершился ли процесс успешно, чтоsubprocess.check_call()
иsubprocess.check_output()
делать (где последний также возвращает стандартный вывод законченного подпроцесса). Точно так же вы должны обычно использоватьcheck=True
с,subprocess.run()
если вам не нужно, чтобы подпроцесс возвращал статус ошибки.На практике, с помощью
check=True
илиsubprocess.check_*
, Python генерируетCalledProcessError
исключение, если подпроцесс возвращает ненулевое состояние выхода.Распространенной ошибкой
subprocess.run()
является отсутствиеcheck=True
и удивление при сбое нижестоящего кода в случае сбоя подпроцесса.С другой стороны, общая проблема с
check_call()
иcheck_output()
заключалась в том, что пользователи, которые слепо использовали эти функции, были удивлены, когдаgrep
возникло исключение, например, когда не нашли соответствия. (Вgrep
любом случае, вам, вероятно, следует заменить на собственный код Python, как описано ниже.)Все вещи рассчитаны, вам нужно понять, как команды оболочки возвращают код выхода и при каких условиях они возвращают ненулевой (ошибочный) код выхода, и принимать осознанное решение о том, как именно его следует обрабатывать.
Понять и, вероятно, использовать
text=True
акаuniversal_newlines=True
Начиная с Python 3, строки внутри Python являются строками Unicode. Но нет никакой гарантии, что подпроцесс генерирует выходные данные Unicode или строки вообще.
(Если различия не сразу очевидны, рекомендуется Прагматический Юникод Неда Батчелдера , если не прямо, то для чтения. Если хотите, за ссылкой стоит 36-минутная видеопрезентация, хотя самостоятельное чтение страницы, вероятно, займет значительно меньше времени. )
В глубине души Python должен извлечь
bytes
буфер и как-то его интерпретировать. Если он содержит двоичный объект двоичных данных, его не следует декодировать в строку Unicode, потому что это поведение подвержено ошибкам и вызывает ошибки - именно такого рода надоедливое поведение, которое пронизывало многие скрипты Python 2, до того, как появился способ правильно различать закодированный текст и двоичные данные.С помощью
text=True
этого вы сообщаете Python, что фактически ожидаете возврата текстовых данных в кодировке системы по умолчанию и что они должны быть декодированы в строку Python (Unicode) в меру возможностей Python (обычно UTF-8 на любых умеренно до система дат, кроме разве винды?)Если это не то , что вы запрашиваете назад, Python будет просто дать вам
bytes
строки вstdout
иstderr
строк. Может быть , в какой - то позже вы же знаете , что они были текстовые строки в конце концов, и вы знаете , их кодирование. Затем вы можете декодировать их.В Python 3.7 введен более короткий и более описательный и понятный псевдоним
text
для ключевого аргумента, который ранее несколько вводил в заблуждениеuniversal_newlines
.Понять
shell=True
противshell=False
С
shell=True
вами вы передаете одну строку в вашу оболочку, и оболочка берет ее оттуда.С
shell=False
вас передают список аргументов в ОС, минуя оболочку.Когда у вас нет оболочки, вы сохраняете процесс и избавляетесь от довольно значительной скрытой сложности, которая может содержать или не содержать ошибки или даже проблемы с безопасностью.
С другой стороны, когда у вас нет оболочки, у вас нет перенаправления, подстановочного знака, управления заданиями и большого количества других функций оболочки.
Распространенной ошибкой является использование,
shell=True
а затем передача Python списка токенов, или наоборот. В некоторых случаях это срабатывает, но на самом деле плохо определено и может сломаться интересными способами.Общая реплика «но это работает для меня» не является полезным опровержением, если вы точно не понимаете, при каких обстоятельствах она может перестать работать.
Пример рефакторинга
Очень часто функции оболочки могут быть заменены собственным кодом Python. Простые Awk или
sed
скрипты, вероятно, должны быть просто переведены на Python.Чтобы частично проиллюстрировать это, вот типичный, но немного глупый пример, который включает в себя множество функций оболочки.
Некоторые вещи, чтобы отметить здесь:
shell=False
вам не нужны цитаты, которые требует оболочка вокруг строк. В любом случае помещать кавычки - это ошибка.Реорганизованный код также показывает, насколько действительно полезна оболочка для вас с очень кратким синтаксисом - к лучшему или к худшему. Python говорит явно лучше , чем неявное , но код Python является довольно многословным и , возможно , выглядит более сложным , чем это на самом деле. С другой стороны, он предлагает ряд точек, где вы можете захватить контроль посреди чего-то другого, что тривиально иллюстрируется улучшением, которое мы можем легко включить в имя хоста вместе с выводом команды оболочки. (Это ни в коем случае не является сложной задачей в оболочке, но за счет еще одной утечки и, возможно, другого процесса.)
Общие конструкции оболочки
Для полноты изложения приведем краткие пояснения некоторых из этих функций оболочки и некоторые примечания о том, как их можно заменить собственными средствами Python.
glob.glob()
или очень часто простым сравнением строк Python, напримерfor file in os.listdir('.'): if not file.endswith('.png'): continue
. Bash имеет различные другие средства расширения, такие как.{png,jpg}
расширение скобок,{1..100}
а также расширение тильды (~
распространяется на ваш домашний каталог и, в более общем случае,~account
на домашний каталог другого пользователя)$SHELL
или$my_exported_var
иногда могут просто заменяться переменными Python. Экспортируемые переменные оболочки доступны, например, какos.environ['SHELL']
(смысл вexport
том, чтобы сделать переменную доступной для подпроцессов - переменная, которая недоступна подпроцессам, очевидно, не будет доступна для Python, выполняющего роль подпроцесса оболочки, или наоборот.env=
Ключевое слово Аргумент кsubprocess
методам позволяет вам определять среду подпроцесса как словарь, так что это один из способов сделать переменную Python видимой для подпроцесса). Сshell=False
вами нужно будет разобраться, как убрать любые цитаты; например,cd "$HOME"
эквивалентноos.chdir(os.environ['HOME'])
без кавычек вокруг имени каталога. (Очень частоcd
в любом случае это бесполезно или не нужно, и многие начинающие опускают двойные кавычки вокруг переменной и обходятся ею до одного дня ... )grep 'foo' <inputfile >outputfile
открываетoutputfile
для записи иinputfile
для чтения и передает его содержимое в качестве стандартного ввода томуgrep
, чей стандартный вывод затем попадает вoutputfile
. Обычно это не сложно заменить на собственный код Python.echo foo | nl
запускает два подпроцесса, где стандартный выводecho
- это стандартный вводnl
(на уровне ОС, в Unix-подобных системах это дескриптор одного файла). Если вы не можете заменить один или оба конца конвейера собственным кодом Python, возможно, в конце концов подумайте об использовании оболочки, особенно если конвейер содержит более двух или трех процессов (хотя посмотрите наpipes
модуль в стандартной библиотеке Python или на число более современных и универсальных сторонних конкурентов).ls -l /
это эквивалентно,'ls' '-l' '/'
но цитирование литералов совершенно необязательно. Строки без кавычек, содержащие метасимволы оболочки, подвергаются расширению параметров, токенизации пробелов и расширению подстановочных знаков; двойные кавычки предотвращают токенизацию пробелов и расширение подстановочных знаков, но допускают расширения параметров (подстановка переменных, подстановка команд и обработка обратной косой черты). Это просто в теории, но может вызвать недоумение, особенно когда есть несколько уровней интерпретации (например, команда удаленной оболочки).Понять разницу между
sh
Bash иsubprocess
запускает команды оболочки,/bin/sh
если только вы специально не запрашиваете иное (кроме, конечно, в Windows, где используется значениеCOMSPEC
переменной). Это означает, что различные функции Bash-only, такие как массивы и[[
т. Д. , Недоступны.Если вам нужно использовать синтаксис Bash-only, вы можете передать путь к оболочке как
executable='/bin/bash'
(где, конечно, если ваш Bash установлен где-то еще, вам нужно изменить путь).A
subprocess
отделен от своего родителя и не может его изменитьНесколько распространенная ошибка - делать что-то вроде
который, помимо отсутствия элегантности, также выдает принципиальное непонимание «под» части названия «подпроцесс».
Дочерний процесс выполняется полностью отдельно от Python, и когда он завершается, Python не имеет представления о том, что он сделал (кроме неопределенных индикаторов, которые он может вывести из состояния выхода и вывода из дочернего процесса). Ребенок обычно не может изменить окружающую среду родителя; он не может установить переменную, изменить рабочий каталог или, во многих словах, связаться со своим родителем без сотрудничества с родителем.
Непосредственное исправление в этом конкретном случае заключается в запуске обеих команд в одном подпроцессе;
хотя очевидно, что этот конкретный вариант использования вообще не требует оболочки. Помните, что вы можете манипулировать средой текущего процесса (и, следовательно, его потомками) через
или передать настройку среды дочернему процессу с
(не говоря уже об очевидном рефакторинге
subprocess.run(['echo', 'bar'])
;echo
конечно, это плохой пример того, что нужно запускать в подпроцессе).Не запускайте Python из Python
Это немного сомнительный совет; безусловно, существуют ситуации, когда это имеет смысл или даже является абсолютным требованием для запуска интерпретатора Python как подпроцесса из сценария Python. Но очень часто правильный подход заключается в
import
том, чтобы просто использовать другой модуль Python в вызывающем скрипте и напрямую вызывать его функции.Если другой скрипт Python находится под вашим контролем и не является модулем, рассмотрите возможность его преобразования в один . (Этот ответ уже слишком длинный, поэтому я не буду вдаваться в подробности.)
Если вам нужен параллелизм, вы можете запускать функции Python в подпроцессах с
multiprocessing
модулем. Кроме того, существуетthreading
несколько задач, которые выполняются в одном процессе (что является более легким и дает вам больше контроля, но также более ограничено в том, что потоки в процессе тесно связаны и связаны с одним GIL .)источник
run()
вслепую. Отсутствиеcheck=True
вызвало ошибку, которую можно было бы избежать, если бы использовался check_call - в названии есть «check», вы не можете его потерять - это правильное значение по умолчанию: не игнорируйте ошибки молча. Я не читал дальше.sh
но вы меня опередили. Я пытаюсь изложить детали достаточно подробно, чтобы помочь новичкам, для которых эти ловушки не очевидны, так что это становится немного длинным. Ваш должен быть вполне достаточно в противном случае; +1stderr/stdout = subprocess.PIPE
это более высокую производительность, чем настройки по умолчанию?os.system()
.Назовите это с подпроцессом
Похоже, ошибка, которую вы получаете, потому что на сервере нет модуля подкачки, вы должны установить на сервере своп, а затем снова запустить скрипт
источник
swap
Модуль, очевидно , есть, потому что , выполнив команду из работ оболочки.shell=True
то вы должны использовать список для передачи нескольких аргументов, т.е. использовать['a', 'b', 'c']
вместо'a b c'
. Хотя наивное разделение не будет работать из-за> file
(перенаправления оболочки) в команде. Более подробная информацияВозможно, вы используете программу bash с параметром -c для выполнения команд:
источник
subprocess.check_output(bashCommand, shell=True)
делает то же самое. Если ваша команда является статической строкой, попробуйте разобрать ее в списке самостоятельно и избегайтеshell=True
; хотя в этом случае вам все равно понадобится оболочка для перенаправления, иначе вам нужно будетwith open('test.nt', 'w') as dest: output = subprocess.check_output(['cwm' ,'--rdf', 'test.rdf', '--ntriples'], stdout=dest, shell=False)
/bin/sh
(используется подпроцессом) не обязательноbash
(нельзя использовать bashisms). Хотя можно использоватьexecutable='/bin/bash
при желании. Вот пример кодаcheck_output()
здесь бесполезен (выход всегда пуст из-за> file
перенаправления; используйтеcheck_call()
вместо него.Вы можете использовать
subprocess
, но я всегда чувствовал, что это не был «Pythonic» способ сделать это. Поэтому я создал Sultan (бесстыдный плагин), который облегчает запуск функций командной строки.https://github.com/aeroxis/sultan
источник
В соответствии с ошибкой на сервере отсутствует пакет с именем swap . Это
/usr/bin/cwm
требует этого. Если вы используете Ubuntu / Debian, установитеpython-swap
с помощью aptitude.источник
swap
либо не должен был импортировать его в первую очередь. ты можешьimport swap
вручную? это работает?sys.path
где это работает, а где нет. Затем попробуйте найти папку подкачки или swap.py в распечатанных папках. Как сказал Свен, с этими путями может быть проблема, и это поможет вам разобраться.Также вы можете использовать «os.popen». Пример:
Вывод:
источник
subprocess
модуль».os.popen
больше не имеет этого предупреждения, иsubprocess.Popen()
теперь просто тонкая оболочка .Чтобы запустить команду без оболочки, передайте команду в виде списка и реализуйте перенаправление в Python, используя
[subprocess]
:Примечание: нет
> test.nt
в конце.stdout=file
реализует перенаправление.Чтобы запустить команду с использованием оболочки в Python, передайте команду в виде строки и включите
shell=True
:Вот эта оболочка отвечает за перенаправление вывода (
> test.nt
есть в команде).Чтобы запустить команду bash, которая использует bashisms, явно укажите исполняемый файл bash, например, для эмуляции подстановки процесса bash :
источник
.split()
стоит упомянуть, что этого недостаточно, когда есть строки в кавычках и т. Д. Существует отдельная подпрограмма,shlex.split()
которая справляется со сколь угодно сложным синтаксисом оболочки..split()
работает в этом случае.shlex.split()
иногда может быть полезным, но в некоторых случаях также может не сработать. Есть очень много вещей, которые можно упомянуть. Вы можете начать со ссылки на описание подпрограммы, приведенной выше.Питонический способ сделать это использует
subprocess.Popen
subprocess.Popen
принимает список, в котором первый элемент - это команда, которая должна быть выполнена, за которой следуют аргументы командной строки.Например:
источник
echo -v '"Hello Again!"'
с одинарными кавычками вокруг двойных кавычек.subprocesss.Popen
необходимо управлять результирующим объектом процесса (как минимум, выполнить a,wait()
чтобы предотвратить его превращение в процесс зомби).