J'ai commencé dans ce trou de lapin comme un moyen de me familiariser avec la façon de créer un script de configuration en python. Le choix de python était simplement enraciné dans ma familiarité avec lui alors que je suis sûr qu'il y aurait de meilleures alternatives que python pour cette tâche.
Le but de ce script était d'installer ROS sur la machine exécutant le script et également de configurer l'environnement catkin. Les directions peuvent être trouvées ici et ici , respectivement.
Le script tel qu'il se trouve actuellement est le suivant:
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"])
Lorsque le script est actuellement exécuté, il génère une erreur avec l'erreur:
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
J'ai vérifié que la commande fonctionne correctement lorsqu'elle est exécutée manuellement à partir d'une fenêtre de terminal, et en tant que telle, je pense que c'est un malentendu fondamental sur la façon dont ce script et sa portée sont traités dans le système d'exploitation. La partie qui me cause beaucoup de confusion est la raison pour laquelle il se plaint de ne pas pouvoir localiser le répertoire fourni, alors que j'ai vérifié que ce répertoire existe. Lorsque la commande est plutôt imprimée à partir de python et collée dans une fenêtre de terminal, aucune erreur n'est rencontrée.
la source
os.chdir()
cwd
argument àcall
Réponses:
Par défaut,
subprocess.call
n'utilise pas de shell pour exécuter nos commandes, vous ne pouvez donc pas shell commecd
.Pour utiliser un shell pour exécuter vos commandes, utilisez
shell=True
comme paramètre. Dans ce cas, il est recommandé de passer vos commandes comme une chaîne unique plutôt que comme une liste. Et comme il est géré par un shell, vous pouvez également l'utiliser~/
dans votre chemin:la source
os.chdir()
?subprocess.call(['catkin_make'], cwd=os.path.expanduser('~/catkin_ws/src'))
?shell=True
appellera le shell par défaut, qui est un tiret. Si un script qui OP contient des bashismes, il peut se casser. J'ai ajouté la modification à ma réponse, une solution alternative serait d'appeler explicitement un shell spécifique. Particulièrement utile si quelqu'un a affaire au script cshshell=True
même avec des commandes fixes ouvre des failles de sécurité (par exemple, shellshock pourrait être déclenché sur un système vulnérable). La règle de base: si vous pouvez éviter d' utiliser ,shell=True
vous devez éviter. Lecwd
paramètre est là pour faire exactement le type d'appel que l'OP veut.subprocess.call()
attend une liste, le premier élément étant évidemment une commande shell légitime. Comparez cela par exemple:Dans votre cas,
subprocess.call(["(cd "+ os.path.expanduser('~') + "/catkin_ws/src)"])
attendez-vous à trouver un binaire qui ressemble à cela (notez la barre oblique inverse désignant le caractère de l'espace):Cela est traité comme un seul nom qui doit résider quelque part sur votre système. Ce que vous voudriez vraiment faire, c'est:
Notez que j'ai supprimé les parenthèses autour de la virgule, car il n'y a aucune raison d'utiliser le sous-shell.
MODIFIER :
Mais il a déjà été mentionné par progo dans les commentaires que l'utilisation
cd
dans ce cas est redondante. La réponse de Florian mentionne également correctement qu'ilsubprocess.call()
n'utilise pas de shell. Vous pouvez aborder cela de deux manières. Un, vous pouvez utilisersubprocess.call("command string",shell=True)
L'autre façon consiste à appeler explicitement un shell spécifique. Ceci est particulièrement utile si vous souhaitez exécuter un script qui nécessite un shell spécifique. Ainsi, vous pourriez faire:
la source
call()
ne s'attend pas à une commande shell légitime; il s'attend à trouver un chemin vers un exécutable réel. Et appeler un autonomecd
ne sert à rien: le CWD est une variable spécifique au processus qui cesse d'exister une fois le processus terminé.cd
cela ne ferait rien ici. . . . Mais en ce qui concerne "légitime", c'est toujours une formulation appropriée, je crois - si je donnesubprocess.call()
quelque chose qu'il ne peut pas trouver, comme['ls -l']
, ce ne sera pas légitimeUtilisez
os.chdir()
plutôt.Mis à part les problèmes mentionnés dans les réponses existantes, je ne préférerais pas utiliser
shell=True
nisubprocess.call()
ici pour changer de répertoire.Python a sa propre façon de changer de répertoire
os.chdir()
(n'oubliez pasimport os
).~
("domicile") peut être défini de plusieurs manières, entre autresos.environ["HOME"]
.Les raisons de préférer cela
shell=True
peuvent être lues icila source
Notez que l'utilisation
os.chdir()
peut provoquer des effets secondaires involontaires, par exemple si vous utilisez le multithreading .subprocess
toutes les méthodes fournissent uncwd
argument de mot clé qui exécutera le sous-processus demandé dans ce répertoire, sans affecter les autres parties de votre processus python.la source