Я пишу программу на Python, которая передает аргументы скрипту оболочки.

Вот мой код на Python:

import subprocess

Process=subprocess.Popen('./copyImage.sh %s' %s str(myPic.jpg))

И мой "copyImage.sh":

#!/bin/sh

cp /home/pi/project/$1 /home/pi/project/newImage.jpg

Я могу запустить скрипт на терминале без проблем. Но при выполнении кода Python терминал вернул "NameError: name 'myPic' is not defined".

Если я изменю синтаксис на

Process=subprocess.Popen('./copyImage.sh %s' %s "myPic.jpg")

Затем терминал вернул "OSError: [Errno 2] No such file or directory".

Я следовал этому: Python: выполнение оболочки сценарий с аргументами (переменными), но аргумент не читается в сценарии оболочки, но это не помогло.

2
RRWW 15 Дек 2015 в 03:31

4 ответа

Лучший ответ

Модуль subprocess ожидает список аргументов, а не разделенную пробелами строку. То, как вы попытались, заставило python искать программу с именем "copyImage.sh myPic.jpg" и вызывать ее без аргументов, тогда как вы хотели найти программу с именем copyImage.sh и вызывать ее с одним аргументом.

subprocess.check_call(['copyImage.sh', 'myPic.jpg'])

Я также хочу упомянуть, поскольку ваш сценарий просто вызывает copy в оболочке, вам, вероятно, следует исключить посредника и просто использовать python shutil.copy напрямую. Это более подходящий инструмент, чем запуск подпроцесса для этой задачи.

2
wim 15 Дек 2015 в 00:44

Безопасный и надежный способ - это:

subprocess.Popen(["./copyImage.sh", "myPic.jpg"])

Ваша первая попытка не удалась, потому что строковым литералам нужны кавычки в Python. Второй не удался, потому что Popen не запускает оболочку по умолчанию (вопрос, который вы связываете, задает Shell=true, чтобы сделать это, но он хрупок и плох).

1
that other guy 15 Дек 2015 в 00:36

Хотя у вас есть 2 ответа, которые показывают, как использовать subprocess с итерацией для аргументов, и я бы порекомендовал пойти одним из этих способов, для полноты вы можете использовать строку, содержащую полную команду, если вы укажете shell=True , но тогда вы несете ответственность за все цитаты и все такое, что для аргументов.

Process=subprocess.Popen('./copyImage.sh %s' % shlex.quote("myPic.jpg"), shell=True)

Обратите внимание: помимо добавления shell=True я передаю аргумент через shlex.quote, чтобы он мог обрабатывать экранирование любых специальных символов, чтобы сделать его немного более безопасным, если имя файла было получено из пользовательского ввода, в противном случае он может включать ; и другую команду для запуска, например , Ввод, такой как myPic.jpg; rm -rf ~, может привести к тому, что при выполнении будут происходить плохие вещи.

Если вы не укажете shell=True, модуль subrpocess фактически будет искать исполняемый файл с именем copyImage.sh myPic.jpg с пробелом и обоими словами в качестве имени исполняемого файла для запуска.

Еще два замечания: для python 2 вместо shlex.quote используйте pipes.quote. Кроме того, сценарий оболочки выше не заключает в кавычки свои аргументы, поэтому не будет работать с именами с пробелами или другими специальными символами. Он должен быть модифицирован, чтобы заключать в кавычки его переменные (который является всегда хорошая идея):

#!/bin/sh

cp /home/pi/project/"$1" /home/pi/project/newImage.jpg

С немного другим сценарием:

#!/bin/bash
printf 'Arg 1 is: %s\n' "$1"

Мы можем увидеть эту работу следующим образом:

subprocess.check_call("./demoScript.sh %s" % shlex.quote("This has ; bad stuff"), shell=True)

Который производит следующий вывод stdout

Arg 1 is: This has ; bad stuff
-1
Community 13 Апр 2017 в 12:36

Использование os.system call - это путь:

  1. os.system находит ваш shell-скрипт в среде
  2. Вы можете добавить столько аргументов, сколько вам нужно, к целевому сценарию оболочки

Примере:

os.system('myshellscript1 ' + arg1 + ' ' + arg2)
4
david m lee 6 Апр 2019 в 21:55