Запуск команд Bash в Python

299

На моей локальной машине я запускаю скрипт 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, и это работает ...

Кто-нибудь знает, что происходит?

MKN
источник
2
Кажется, что есть разница в окружающей среде в зависимости от того, как вы работаете cwm. Может быть, у вас есть какая-то конфигурация, .bashrcкоторая настраивает среду для интерактивного использования bash?
Свен Марнач
Вы пытались запустить команду из командной строки при входе в систему на сервере? Ваше сообщение просто говорит, что вы "вставили [это] в терминал".
Свен Марнач
@Sven: да я имел ввиду, что я запускал команду прямо в терминале сервера
mkn
Кажется, есть разница в PYTHONPATH в зависимости от того, как вы бежите cwm. Или, может быть, есть разница в PATH, и cwmназываются разные версии . Или разные версии Python. Это действительно трудно понять без доступа к машине ...
Свен Марнах

Ответы:

314

Не используйте os.system. Это устарело в пользу подпроцесса . Из документации : «Этот модуль намерен заменить несколько старых модулей и функций: os.system, os.spawn».

Как в вашем случае:

bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
import subprocess
process = subprocess.Popen(bashCommand.split(), stdout=subprocess.PIPE)
output, error = process.communicate()
user225312
источник
8
Это не делало то, что я хотел, когда мне нужно было выполнить cd 'path\to\somewhere'другую команду bash, которую нужно было где-то запустить. @ user225312
AWrightIV
36
@AWrightIV Если вам нужно, чтобы ваш подпроцесс работал в определенном рабочем каталоге, вы можете использовать cwdаргумент для Popen:subprocess.Popen(..., cwd='path\to\somewhere')
водонепроницаемый
7
Для моей команды мне понадобился shell = True, как здесь; stackoverflow.com/questions/18962785/…
user984003
4
В этом случае лучше использовать shlex.split () вместо string.split ()
Алексей Свиридов
4
... ( stdout=fileв этом случае перенаправляет вывод в файл. Он реализует > file). Было бы неправильно передавать ..., '>', 'file']последнюю команду, ожидающую перенаправление (она не будет работать без оболочки, и если вы используете оболочку, вы должны передать команду в виде строки)
jfs
186

Чтобы немного расширить предыдущие ответы, есть ряд деталей, которые обычно упускаются из виду.

  • Предпочитаю subprocess.run()более subprocess.check_call()и друзьями в течение subprocess.call()более чем subprocess.Popen()над os.system()болееos.popen()
  • Понять и, вероятно, использовать text=True, иначе universal_newlines=True.
  • Понять значение shell=Trueили то, shell=Falseкак оно меняет цитирование, и доступность удобства оболочки.
  • Понять разницу между shBash и
  • Понять, как подпроцесс отделен от своего родителя и, как правило, не может изменить родителя.
  • Избегайте запуска интерпретатора Python как подпроцесса Python.

Эти темы рассматриваются более подробно ниже.

Предпочитаю subprocess.run()илиsubprocess.check_call()

Эта subprocess.Popen()функция - рабочая лошадка низкого уровня, но ее сложно использовать правильно, и в итоге вы копируете / вставляете несколько строк кода ... которые обычно уже существуют в стандартной библиотеке как набор высокоуровневых функций-оболочек для различных целей, которые представлены более подробно в следующем.

Вот параграф из документации :

Рекомендуемый подход к вызову подпроцессов заключается в использовании run()функции для всех случаев использования, которые она может обработать. Для более сложных вариантов использования базовый 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():

subprocessМодуль предоставляет более мощные средства для порождения новых процессов и получения их результатов; использование этого модуля предпочтительнее, чем использование этой функции.

Проблемы в том system(), что он явно зависит от системы и не предлагает способов взаимодействия с подпроцессом. Он просто работает со стандартным выводом и стандартной ошибкой вне досягаемости Python. Единственная информация, которую Python получает обратно, - это состояние выхода команды (ноль означает успех, хотя значение ненулевых значений также в некоторой степени зависит от системы).

PEP-324 (о котором уже упоминалось выше) содержит более подробное обоснование причин проблем os.systemи способов subprocessих решения.

os.popen()Раньше был еще более обескуражен :

Устаревший с версии 2.6: эта функция устарела. Используйте subprocessмодуль.

Однако с тех пор в 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строк. Может быть , в какой - то позже вы же знаете , что они были текстовые строки в конце концов, и вы знаете , их кодирование. Затем вы можете декодировать их.

normal = subprocess.run([external, arg],
    stdout=subprocess.PIPE, stderr=subprocess.PIPE,
    check=True,
    text=True)
print(normal.stdout)

convoluted = subprocess.run([external, arg],
    stdout=subprocess.PIPE, stderr=subprocess.PIPE,
    check=True)
# You have to know (or guess) the encoding
print(convoluted.stdout.decode('utf-8'))

В Python 3.7 введен более короткий и более описательный и понятный псевдоним textдля ключевого аргумента, который ранее несколько вводил в заблуждение universal_newlines.

Понять shell=Trueпротивshell=False

С shell=Trueвами вы передаете одну строку в вашу оболочку, и оболочка берет ее оттуда.

С shell=Falseвас передают список аргументов в ОС, минуя оболочку.

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

С другой стороны, когда у вас нет оболочки, у вас нет перенаправления, подстановочного знака, управления заданиями и большого количества других функций оболочки.

Распространенной ошибкой является использование, shell=Trueа затем передача Python списка токенов, или наоборот. В некоторых случаях это срабатывает, но на самом деле плохо определено и может сломаться интересными способами.

# XXX AVOID THIS BUG
buggy = subprocess.run('dig +short stackoverflow.com')

# XXX AVOID THIS BUG TOO
broken = subprocess.run(['dig', '+short', 'stackoverflow.com'],
    shell=True)

# XXX DEFINITELY AVOID THIS
pathological = subprocess.run(['dig +short stackoverflow.com'],
    shell=True)

correct = subprocess.run(['dig', '+short', 'stackoverflow.com'],
    # Probably don't forget these, too
    check=True, text=True)

# XXX Probably better avoid shell=True
# but this is nominally correct
fixed_but_fugly = subprocess.run('dig +short stackoverflow.com',
    shell=True,
    # Probably don't forget these, too
    check=True, text=True)

Общая реплика «но это работает для меня» не является полезным опровержением, если вы точно не понимаете, при каких обстоятельствах она может перестать работать.

Пример рефакторинга

Очень часто функции оболочки могут быть заменены собственным кодом Python. Простые Awk или sedскрипты, вероятно, должны быть просто переведены на Python.

Чтобы частично проиллюстрировать это, вот типичный, но немного глупый пример, который включает в себя множество функций оболочки.

cmd = '''while read -r x;
   do ping -c 3 "$x" | grep 'round-trip min/avg/max'
   done <hosts.txt'''

# Trivial but horrible
results = subprocess.run(
    cmd, shell=True, universal_newlines=True, check=True)
print(results.stdout)

# Reimplement with shell=False
with open('hosts.txt') as hosts:
    for host in hosts:
        host = host.rstrip('\n')  # drop newline
        ping = subprocess.run(
             ['ping', '-c', '3', host],
             text=True,
             stdout=subprocess.PIPE,
             check=True)
        for line in ping.stdout.split('\n'):
             if 'round-trip min/avg/max' in line:
                 print('{}: {}'.format(host, line))

Некоторые вещи, чтобы отметить здесь:

  • При этом shell=Falseвам не нужны цитаты, которые требует оболочка вокруг строк. В любом случае помещать кавычки - это ошибка.
  • Часто имеет смысл запускать как можно меньше кода в подпроцессе. Это дает вам больше контроля над выполнением из вашего кода Python.
  • Сказав это, сложные конвейеры оболочки утомительны и иногда сложно переопределить в Python.

Реорганизованный код также показывает, насколько действительно полезна оболочка для вас с очень кратким синтаксисом - к лучшему или к худшему. 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 или на число более современных и универсальных сторонних конкурентов).
  • Управление заданиями позволяет прерывать задания, запускать их в фоновом режиме, возвращать их на передний план и т. Д. Основные сигналы Unix для остановки и продолжения процесса, конечно же, доступны и в Python. Но задания - это высокоуровневая абстракция в оболочке, которая включает группы процессов и т. Д., Которые вы должны понимать, если хотите сделать что-то подобное из Python.
  • Цитирование в оболочке может привести к путанице, пока вы не поймете, что все это в основном строка. Таким образом, ls -l /это эквивалентно, 'ls' '-l' '/'но цитирование литералов совершенно необязательно. Строки без кавычек, содержащие метасимволы оболочки, подвергаются расширению параметров, токенизации пробелов и расширению подстановочных знаков; двойные кавычки предотвращают токенизацию пробелов и расширение подстановочных знаков, но допускают расширения параметров (подстановка переменных, подстановка команд и обработка обратной косой черты). Это просто в теории, но может вызвать недоумение, особенно когда есть несколько уровней интерпретации (например, команда удаленной оболочки).

Понять разницу между shBash и

subprocessзапускает команды оболочки, /bin/shесли только вы специально не запрашиваете иное (кроме, конечно, в Windows, где используется значение COMSPECпеременной). Это означает, что различные функции Bash-only, такие как массивы и [[т. Д. , Недоступны.

Если вам нужно использовать синтаксис Bash-only, вы можете передать путь к оболочке как executable='/bin/bash'(где, конечно, если ваш Bash установлен где-то еще, вам нужно изменить путь).

subprocess.run('''
    # This for loop syntax is Bash only
    for((i=1;i<=$#;i++)); do
        # Arrays are Bash-only
        array[i]+=123
    done''',
    shell=True, check=True,
    executable='/bin/bash')

A subprocessотделен от своего родителя и не может его изменить

Несколько распространенная ошибка - делать что-то вроде

subprocess.run('foo=bar', shell=True)
subprocess.run('echo "$foo"', shell=True)  # Doesn't work

который, помимо отсутствия элегантности, также выдает принципиальное непонимание «под» части названия «подпроцесс».

Дочерний процесс выполняется полностью отдельно от Python, и когда он завершается, Python не имеет представления о том, что он сделал (кроме неопределенных индикаторов, которые он может вывести из состояния выхода и вывода из дочернего процесса). Ребенок обычно не может изменить окружающую среду родителя; он не может установить переменную, изменить рабочий каталог или, во многих словах, связаться со своим родителем без сотрудничества с родителем.

Непосредственное исправление в этом конкретном случае заключается в запуске обеих команд в одном подпроцессе;

subprocess.run('foo=bar; echo "$foo"', shell=True)

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

os.environ['foo'] = 'bar'

или передать настройку среды дочернему процессу с

subprocess.run('echo "$foo"', shell=True, env={'foo': 'bar'})

(не говоря уже об очевидном рефакторинге subprocess.run(['echo', 'bar']); echoконечно, это плохой пример того, что нужно запускать в подпроцессе).

Не запускайте Python из Python

Это немного сомнительный совет; безусловно, существуют ситуации, когда это имеет смысл или даже является абсолютным требованием для запуска интерпретатора Python как подпроцесса из сценария Python. Но очень часто правильный подход заключается в importтом, чтобы просто использовать другой модуль Python в вызывающем скрипте и напрямую вызывать его функции.

Если другой скрипт Python находится под вашим контролем и не является модулем, рассмотрите возможность его преобразования в один . (Этот ответ уже слишком длинный, поэтому я не буду вдаваться в подробности.)

Если вам нужен параллелизм, вы можете запускать функции Python в подпроцессах с multiprocessingмодулем. Кроме того, существует threadingнесколько задач, которые выполняются в одном процессе (что является более легким и дает вам больше контроля, но также более ограничено в том, что потоки в процессе тесно связаны и связаны с одним GIL .)

tripleee
источник
2
Более подробное изложение того, как можно избежать вызова Python как подпроцесса, см. В этом ответе по касательно схожему вопросу.
tripleee
4
это уму непостижимо, что мне пришлось опубликовать новый ответ на такой базовый вопрос, чтобы показать, как идиоматически запустить команду из вопроса. Ваш ответ длинный, но я не вижу такого примера. Не связано: избегать грузоперевозок. Если check_call () работает в вашем случае, используйте его. Я должен был исправить код, который использовался run()вслепую. Отсутствие check=Trueвызвало ошибку, которую можно было бы избежать, если бы использовался check_call - в названии есть «check», вы не можете его потерять - это правильное значение по умолчанию: не игнорируйте ошибки молча. Я не читал дальше.
Jfs
1
@jfs Спасибо за отзыв, я планировал добавить раздел о Bash vs, shно вы меня опередили. Я пытаюсь изложить детали достаточно подробно, чтобы помочь новичкам, для которых эти ловушки не очевидны, так что это становится немного длинным. Ваш должен быть вполне достаточно в противном случае; +1
трипл
Имеет ли stderr/stdout = subprocess.PIPEэто более высокую производительность, чем настройки по умолчанию?
Стрингеры
1
@ Стрингеры я не проверял, но не понимаю, почему так должно быть. Если вы соединяете эти каналы с чем-то, что выполняет некоторую обработку, то, конечно, эта обработка должна учитываться; но это не происходит в самой трубе. По умолчанию это вообще не захватывает stdout или stderr, то есть то, что там печатается, выходит из-под видимости и контроля Python, как и с os.system().
tripleee
41

Назовите это с подпроцессом

import subprocess
subprocess.Popen("cwm --rdf test.rdf --ntriples > test.nt")

Похоже, ошибка, которую вы получаете, потому что на сервере нет модуля подкачки, вы должны установить на сервере своп, а затем снова запустить скрипт

Якоб Бауэр
источник
3
swapМодуль, очевидно , есть, потому что , выполнив команду из работ оболочки.
Свен Марнач
2
Не на сервере, когда он запускает его на сервере, возникает ошибка импорта.
Якоб Бауэр
@mkn: «Тогда я просто скопировал этот вывод, вставил копию в терминал и нажал Enter, и все работает ...» - Вы пробовали это на сервере или на своей машине?
Свен Марнач
Вы работаете с этим на автономном компьютере, но он не работает, когда вы запускаете его на своем сервере? Или вы можете запустить его на серверном терминале, но не на самом сервере
Jakob Bowyer
1
это неправильно. Если вы не используете, shell=Trueто вы должны использовать список для передачи нескольких аргументов, т.е. использовать ['a', 'b', 'c']вместо 'a b c'. Хотя наивное разделение не будет работать из-за > file(перенаправления оболочки) в команде. Более подробная информация
JFS
18

Возможно, вы используете программу bash с параметром -c для выполнения команд:

bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
output = subprocess.check_output(['bash','-c', bashCommand])
бритва
источник
2
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)
перестроить
Примечание @tripleee: /bin/sh(используется подпроцессом) не обязательно bash(нельзя использовать bashisms). Хотя можно использовать executable='/bin/bashпри желании. Вот пример кода
JFS
2
это первый ответ, в котором команда должна начинаться успешно (принятые и 2-е популярные ответы просто неверны. Незначительный спор: check_output()здесь бесполезен (выход всегда пуст из-за > fileперенаправления; используйте check_call()вместо него.
jfs
16

Вы можете использовать subprocess, но я всегда чувствовал, что это не был «Pythonic» способ сделать это. Поэтому я создал Sultan (бесстыдный плагин), который облегчает запуск функций командной строки.

https://github.com/aeroxis/sultan

Дэвид Дэниел
источник
3
Отлично сработано! Гораздо чище и понятнее, чем подпроцесс.
mjd2
Спасибо вам большое! Я рад слышать, что!
Дэвид Дэниел
2
Это должно быть честно принято в стандартной библиотеке.
Джошуа Детвилер
1
Есть ли способ захватить вывод из терминала с помощью султана?
Авас
Да, вы можете @alvas ... Вот документы о том, как это сделать: sultan.readthedocs.io/en/latest/…
Дэвид Даниэль
7

В соответствии с ошибкой на сервере отсутствует пакет с именем swap . Это /usr/bin/cwmтребует этого. Если вы используете Ubuntu / Debian, установите python-swapс помощью aptitude.

кичик
источник
но он работает, когда я запускаю его прямо в терминале ... так что своп должен быть там, не так ли?
мкн
Есть два варианта. либо он не может найти, swapлибо не должен был импортировать его в первую очередь. ты можешь import swapвручную? это работает?
Кичик
хм, я не могу. Если я запускаю python, набирая python в терминале, а затем набираю import swap, я получаю ошибку «ImportError: Нет модуля с именем swap». Странно то, что он работает, когда я запускаю команду cwm прямо в терминале сервера
mkn
Попробуйте напечатать, sys.pathгде это работает, а где нет. Затем попробуйте найти папку подкачки или swap.py в распечатанных папках. Как сказал Свен, с этими путями может быть проблема, и это поможет вам разобраться.
Кичик
4

Также вы можете использовать «os.popen». Пример:

import os

command = os.popen('ls -al')
print(command.read())
print(command.close())

Вывод:

total 16
drwxr-xr-x 2 root root 4096 ago 13 21:53 .
drwxr-xr-x 4 root root 4096 ago 13 01:50 ..
-rw-r--r-- 1 root root 1278 ago 13 21:12 bot.py
-rw-r--r-- 1 root root   77 ago 13 21:53 test.py

None
ricardo130
источник
1
Документация содержит большое красное поле: « устарело с версии 2.6: эта функция устарела. Используйте subprocessмодуль».
tripleee
1
Справедливости ради, os.popenбольше не имеет этого предупреждения, и subprocess.Popen()теперь просто тонкая оболочка .
tripleee
4

Чтобы запустить команду без оболочки, передайте команду в виде списка и реализуйте перенаправление в Python, используя [subprocess]:

#!/usr/bin/env python
import subprocess

with open('test.nt', 'wb', 0) as file:
    subprocess.check_call("cwm --rdf test.rdf --ntriples".split(),
                          stdout=file)

Примечание: нет > test.ntв конце. stdout=fileреализует перенаправление.


Чтобы запустить команду с использованием оболочки в Python, передайте команду в виде строки и включите shell=True:

#!/usr/bin/env python
import subprocess

subprocess.check_call("cwm --rdf test.rdf --ntriples > test.nt",
                      shell=True)

Вот эта оболочка отвечает за перенаправление вывода ( > test.ntесть в команде).


Чтобы запустить команду bash, которая использует bashisms, явно укажите исполняемый файл bash, например, для эмуляции подстановки процесса bash :

#!/usr/bin/env python
import subprocess

subprocess.check_call('program <(command) <(another-command)',
                      shell=True, executable='/bin/bash')
JFS
источник
Возможно, .split()стоит упомянуть, что этого недостаточно, когда есть строки в кавычках и т. Д. Существует отдельная подпрограмма, shlex.split()которая справляется со сколь угодно сложным синтаксисом оболочки.
tripleee
@tripleee .split()работает в этом случае. shlex.split()иногда может быть полезным, но в некоторых случаях также может не сработать. Есть очень много вещей, которые можно упомянуть. Вы можете начать со ссылки на описание подпрограммы, приведенной выше.
Jfs
0

Питонический способ сделать это использует subprocess.Popen

subprocess.Popen принимает список, в котором первый элемент - это команда, которая должна быть выполнена, за которой следуют аргументы командной строки.

Например:

import subprocess

args = ['echo', 'Hello!']
subprocess.Popen(args) // same as running `echo Hello!` on cmd line

args2 = ['echo', '-v', '"Hello Again"']
subprocess.Popen(args2) // same as running 'echo -v "Hello Again!"` on cmd line
RewordedAnswers
источник
Нет, последний пример аналогичен работе echo -v '"Hello Again!"'с одинарными кавычками вокруг двойных кавычек.
tripleee
Также правильно использовать subprocesss.Popen необходимо управлять результирующим объектом процесса (как минимум, выполнить a, wait()чтобы предотвратить его превращение в процесс зомби).
tripleee