python subprocess.call() 没有按预期工作

bee*_*edy 14 python command-line scripts

我开始钻研这个兔子洞,目的是让自己熟悉如何在 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"])
Run Code Online (Sandbox Code Playgroud)

当前运行脚本时,它会出错并显示以下错误:

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
Run Code Online (Sandbox Code Playgroud)

我已经验证该命令在从终端窗口手动执行时可以正常工作,因此我认为这是对如何在操作系统中处理该脚本及其范围的根本误解。引起我很多困惑的部分是为什么它抱怨无法找到提供的目录,而我已验证该目录存在。当命令是从 python 打印并粘贴到终端窗口时,不会遇到错误。

Flo*_*sch 19

默认情况下subprocess.call,不使用 shell 来运行我们的命令,因此您不能对像cd.

要使用 shell 运行您的命令,请使用shell=Trueas 参数。在这种情况下,建议将您的命令作为单个字符串而不是列表传递。由于它由 shell 运行,因此您也可以~/在路径中使用:

subprocess.call("(cd ~/catkin_ws/src && catkin_make)", shell=True)
Run Code Online (Sandbox Code Playgroud)

  • 怎么样`subprocess.call(['catkin_make'], cwd=os.path.expanduser('~/catkin_ws/src'))`? (3认同)

Ser*_*nyy 6

subprocess.call() 需要一个列表,第一项显然是合法的 shell 命令。比较这个例如:

>>> subprocess.call(['echo hello'])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  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
>>> subprocess.call(['echo', 'hello'])
hello
0
Run Code Online (Sandbox Code Playgroud)

在您的情况下,subprocess.call(["(cd "+ os.path.expanduser('~') + "/catkin_ws/src)"])将期望找到看起来像这样的二进制文件(注意指定空格字符的反斜杠):

 cd\ /home/user/catkin_ws/src
Run Code Online (Sandbox Code Playgroud)

这被视为一个单一名称,预计会出现在您系统的某个位置。你真正想做的是:

 subprocess.call(["cd", os.path.expanduser('~') + "/catkin_ws/src"])
Run Code Online (Sandbox Code Playgroud)

请注意,我已经删除了逗号周围的括号,因为没有理由使用 subshel​​l。

编辑

但是progo在评论中已经提到,cd在这种情况下使用是多余的。弗洛里安的回答也正确地提到subprocess.call()不使用外壳。你可以通过两种方式来解决这个问题。一,你可以使用subprocess.call("command string",shell=True)

另一种方法是显式调用特定的 shell。如果您想运行需要特定 shell 的脚本,这尤其有用。因此你可以这样做:

subprocess.call(['bash' , os.path.expanduser('~')  + "/catkin_ws/src"  ) ] )
Run Code Online (Sandbox Code Playgroud)