Я начал с этой кроличьей норы как средства для ознакомления с тем, как можно было бы создать сценарий установки в python. Выбор python был основан на моем знакомстве с ним, хотя я уверен, что для этой задачи найдутся альтернативы лучше, чем python.
Цель этого сценария состояла в том, чтобы установить ROS на компьютере, на котором выполняется сценарий, а также настроить среду catkin. Направления можно найти здесь и здесь , соответственно.
Сценарий, в котором он сейчас находится, выглядит следующим образом:
subprocess.call(["sudo", "sh", "-c", "'echo \"deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main\" > /etc/apt/sources.list.d/ros-latest.list'"])
subprocess.call(["sudo", "apt-key", "adv", "--keyserver", "hkp://ha.pool.sks-keyserver.net:80", "--recv-key", "0xB01FA116"])
subprocess.call(["sudo", "apt-get", "update"])
subprocess.call(["sudo", "apt-get", "install", "ros-kinetic-desktop-full", "-y"])
subprocess.call(["sudo", "rosdep", "init"])
subprocess.call(["rosdep", "update"])
subprocess.call(["echo", '"source /opt/ros/kinetic/setup.bash"', ">>", "~/.bashrc", "source", "~/.bashrc"])
subprocess.call(["sudo", "apt-get", "install", "python-rosinstall", "-y"])
mkdir_p(os.path.expanduser('~') + "/catkin_ws/src")
subprocess.call(["(cd "+ os.path.expanduser('~') + "/catkin_ws/src)"])
subprocess.call(["(cd "+ os.path.expanduser('~') + "/catkin_ws && catkin_make)"])
subprocess.call(["(cd "+ os.path.expanduser('~') + "/catkin_ws && source devel/setup.bash"])
Когда скрипт в настоящий момент выполняется, он выдает ошибку с ошибкой:
Traceback (most recent call last):
File "setup.py", line 46, in <module>
subprocess.call(["(cd "+ os.path.expanduser('~') + "/catkin_ws/src)"])
File "/usr/lib/python2.7/subprocess.py", line 523, in call
return Popen(*popenargs, **kwargs).wait()
File "/usr/lib/python2.7/subprocess.py", line 711, in __init__
errread, errwrite)
File "/usr/lib/python2.7/subprocess.py", line 1343, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory
Я проверил, что команда работает правильно, когда выполняется вручную из окна терминала, и поэтому я считаю, что это фундаментальное недоразумение о том, как этот скрипт и его область действия обрабатываются в ОС. Часть, которая вызывает у меня большую путаницу, заключается в том, что она жалуется, что не может найти предоставленный каталог, хотя я проверил, что этот каталог существует. Когда команда выводится из python и вставляется в окно терминала, ошибок не возникает.
источник
os.chdir()
cwd
аргументcall
Ответы:
По умолчанию
subprocess.call
не используется оболочка для запуска наших команд, поэтому вы не можете использовать такие оболочкиcd
.Чтобы использовать оболочку для запуска ваших команд используйте в
shell=True
качестве параметра. В этом случае рекомендуется передавать ваши команды как одну строку, а не как список. И так как он запускается оболочкой, вы также можете использовать~/
на своем пути:источник
os.chdir()
?subprocess.call(['catkin_make'], cwd=os.path.expanduser('~/catkin_ws/src'))
?shell=True
вызовет оболочку по умолчанию, которая является тире. Если скрипт, который OP содержит bashisms, он может сломаться. Я добавил правку в свой ответ, альтернативным решением будет явный вызов определенной оболочки. Особенно полезно, если кто-то имеет дело с csh-скриптомshell=True
даже с фиксированными командами открывает уязвимости в системе безопасности (например, в уязвимой системе может произойти выстрел из ракушки). Основное правило: если вы можете избежать использования,shell=True
вы должны избегать его.cwd
Параметр там точно делать вид вызова ОП хочет.subprocess.call()
ожидает список, причем первый элемент, очевидно, является допустимой командой оболочки. Сравните это, например:В вашем случае
subprocess.call(["(cd "+ os.path.expanduser('~') + "/catkin_ws/src)"])
вы ожидаете найти двоичный файл, который выглядит так (обратите внимание на обратную косую черту, обозначающую символ пробела):Это рассматривается как единственное имя, которое, как ожидается, будет жить где-то в вашей системе. Что вы действительно хотите сделать, это:
Обратите внимание, что я удалил круглые скобки вокруг запятой, так как нет причины использовать subshell.
РЕДАКТИРОВАТЬ :
Но Progo уже упоминал в комментариях, что использование
cd
в этом случае является излишним. В ответе Флориана также упоминается, чтоsubprocess.call()
не используется оболочка. Вы можете подойти к этому двумя способами. Один, вы могли бы использоватьsubprocess.call("command string",shell=True)
Другой способ - явно вызывать конкретную оболочку. Это особенно полезно, если вы хотите запустить скрипт, который требует определенной оболочки. Таким образом, вы можете сделать:
источник
call()
не ожидает законной команды оболочки; он ожидает найти путь к реальному исполняемому файлу. А вызов автономногоcd
ничего не дает: CWD - это переменная, специфичная для процесса, которая перестает существовать после выхода из процесса.cd
что здесь ничего не получится. , , , Но что касается «законного», это все еще уместное выражение, я полагаю - если я дамsubprocess.call()
что-то, чего не могу найти, например['ls -l']
, это не будет законным,Используйте
os.chdir()
вместо этого.Помимо вопросов, упомянутых в существующих ответах, я бы не хотел использовать
shell=True
ниsubprocess.call()
здесь, чтобы изменить каталог.Python имеет свой собственный способ изменения каталога
os.chdir()
(не забудьтеimport os
).~
(«дом») можно определить несколькими способами, аоos.environ["HOME"]
.Причины, чтобы предпочесть это,
shell=True
можно прочитать здесьисточник
Обратите внимание, что использование
os.chdir()
может вызвать непреднамеренные побочные эффекты, например, если вы используете многопоточность .subprocess
все методы предоставляютcwd
аргумент ключевого слова, который запустит запрошенный подпроцесс в этом каталоге, не затрагивая другие части вашего процесса python.источник