python笔记65 - Python3 subprocess执行cmd命令行获取返回结果

本文详细介绍了Python的subprocess模odule,包括Popen类的使用,参数解析,以及如何处理子进程的输入输出。示例展示了如何通过shell执行命令,处理不同编码的输出,以及如何与子进程交互。此外,还提到了Popen对象的方法,如poll(), wait(), communicate()等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

subprocess 模块允许我们启动一个新进程,并连接到它们的输入/输出/错误管道,从而获取返回值。
Popen 是 subprocess的核心,子进程的创建和管理都靠它处理。

subprocess.Popen

subprocess模块定义了一个类: Popen

class Popen(object):
    """ Execute a child program in a new process.

    For a complete description of the arguments see the Python documentation.

    Arguments:
      args: A string, or a sequence of program arguments.

      bufsize: supplied as the buffering argument to the open() function when
          creating the stdin/stdout/stderr pipe file objects

      executable: A replacement program to execute.

      stdin, stdout and stderr: These specify the executed programs' standard
          input, standard output and standard error file handles, respectively.

      preexec_fn: (POSIX only) An object to be called in the child process
          just before the child is executed.

      close_fds: Controls closing or inheriting of file descriptors.

      shell: If true, the command will be executed through the shell.

      cwd: Sets the current directory before the child is executed.

      env: Defines the environment variables for the new process.

      universal_newlines: If true, use universal line endings for file
          objects stdin, stdout and stderr.

      startupinfo and creationflags (Windows only)

      restore_signals (POSIX only)

      start_new_session (POSIX only)

      pass_fds (POSIX only)

      encoding and errors: Text mode encoding and error handling to use for
          file objects stdin, stdout and stderr.

    Attributes:
        stdin, stdout, stderr, pid, returncode
    """
    _child_created = False  # Set here since __del__ checks it

    def __init__(self, args, bufsize=-1, executable=None,
                 stdin=None, stdout=None, stderr=None,
                 preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS,
                 shell=False, cwd=None, env=None, universal_newlines=False,
                 startupinfo=None, creationflags=0,
                 restore_signals=True, start_new_session=False,
                 pass_fds=(), *, encoding=None, errors=None):
        """Create new Popen instance."""

常用参数:

  • args:shell命令,可以是字符串或者序列类型(如:str, list,元组)
  • bufsize:缓冲区大小。当创建标准流的管道对象时使用,默认-1。
    0:不使用缓冲区
    1:表示行缓冲,仅当universal_newlines=True时可用,也就是文本模式
    正数:表示缓冲区大小
    负数:表示使用系统默认的缓冲区大小。
  • stdin, stdout, stderr:分别表示程序的标准输入、输出、错误句柄
  • preexec_fn:只在 Unix 平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用
  • shell:如果该参数为 True,将通过操作系统的 shell 执行指定的命令。
  • cwd:用于设置子进程的当前目录。
  • env:用于指定子进程的环境变量。如果 env = None,子进程的环境变量将从父进程中继承。
  • encoding:设置编码类型

使用示例

一个简单示例,命令行执行pip

import subprocess
p = subprocess.Popen('pip -V',
                     shell=True,
                     stdout=subprocess.PIPE,
                     stderr=subprocess.STDOUT,
                     )

# 输出stdout
print(p.communicate()[0])

得到结果是byte类型的

b'pip 21.1.2 from e:\\python36\\lib\\site-packages\\pip (python 3.6)\r\r\n'

于是可以添加encoding参数utf-8

import subprocess
p = subprocess.Popen('pip -V',
                     shell=True,
                     stdout=subprocess.PIPE,
                     stderr=subprocess.STDOUT,
                     encoding='utf-8'
                     )

# 输出stdout
print(p.communicate()[0])

此时输出

pip 21.1.2 from e:\python36\lib\site-packages\pip (python 3.6)

如果输出有中文,会出现解码异常
输入java,正常情况是可以输出中文的

import subprocess
p = subprocess.Popen('java',
                     shell=True,
                     stdout=subprocess.PIPE,
                     stderr=subprocess.STDOUT,
                     encoding='utf-8'
                     )

# 输出stdout
print(p.communicate()[0])

但是运行结果就会解码异常

Traceback (most recent call last):
  File "D:/tests.py", line 44, in <module>
    print(p.communicate()[0])
  File "E:\python36\lib\subprocess.py", line 830, in communicate
    stdout = self.stdout.read()
  File "E:\python36\lib\codecs.py", line 321, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd3 in position 0: invalid continuation byte

原因是windows系统编码是gb2312

windows解码

知道windows系统的编码后,设置对应的编码,就可以正常解码了

import subprocess
p = subprocess.Popen('java',
                     shell=True,
                     stdout=subprocess.PIPE,
                     stderr=subprocess.STDOUT,
                     encoding='gb2312'
                     )

# 输出stdout
print(p.communicate()[0])

得到

用法: java [-options] class [args...]
           (执行类)
   或  java [-options] -jar jarfile [args...]
           (执行 jar 文件)
其中选项包括:
    -d32	  使用 32 位数据模型 (如果可用)
    -d64	  使用 64 位数据模型 (如果可用)
    -server	  选择 "server" VM
                  默认 VM 是 server.

也可以在拿到输出结果后decode解码

import subprocess
p = subprocess.Popen('java',
                     shell=True,
                     stdout=subprocess.PIPE,
                     stderr=subprocess.STDOUT,
                     )
# 输出stdout
result = p.communicate()[0]
print(result.decode('gb2312'))

执行python代码,得到stdout内容

接下来写一小段python代码,看执行结果

# xx.py
print("hello world! 这段包含了中文")

使用subprocess.Popen执行,需设置encoding=‘utf-8’

import subprocess
p = subprocess.Popen(['python', 'xx.py'],
                     shell=True,
                     stdout=subprocess.PIPE,
                     stderr=subprocess.STDOUT,
                     encoding='utf-8'
                     )

# 输出stdout
print(p.communicate()[0])

运行结果

hello world! 这段包含了中文

如果python代码有语法异常

# xx.py
print("hello world! 这段包含了中文"x)

此时是可以输出异常内容的

  File "xx.py", line 1
    print("hello world! 这段包含了中文"x)
                                ^
SyntaxError: invalid syntax

Popen 对象方法

Popen 对象方法用到的几个方法

  • poll(): 检查进程是否终止,如果终止返回 returncode,否则返回 None。
  • wait(timeout): 等待子进程终止。
  • communicate(input,timeout): 和子进程交互,发送和读取数据。
  • send_signal(singnal): 发送信号到子进程 。
  • terminate(): 停止子进程,也就是发送SIGTERM信号到子进程。
  • kill(): 杀死子进程。发送 SIGKILL 信号到子进程。

其它方法参考菜鸟教程https://www.runoob.com/w3cnote/python3-subprocess.html

OSError Traceback (most recent call last) Cell In[9], line 1 ----> 1 get_ipython().run_line_magic(&#39;pip&#39;, &#39;install pmdarima&#39;) File /lib/python3.12/site-packages/IPython/core/interactiveshell.py:2480, in InteractiveShell.run_line_magic(self, magic_name, line, _stack_depth) 2478 kwargs[&#39;local_ns&#39;] = self.get_local_scope(stack_depth) 2479 with self.builtin_trap: -> 2480 result = fn(*args, **kwargs) 2482 # The code below prevents the output from being displayed 2483 # when using magics with decorator @output_can_be_silenced 2484 # when the last Python token in the expression is a &#39;;&#39;. 2485 if getattr(fn, magic.MAGIC_OUTPUT_CAN_BE_SILENCED, False): File /lib/python3.12/site-packages/IPython/core/magics/packaging.py:92, in PackagingMagics.pip(self, line) 89 else: 90 python = shlex.quote(python) ---> 92 self.shell.system(" ".join([python, "-m", "pip", line])) 94 print("Note: you may need to restart the kernel to use updated packages.") File /lib/python3.12/site-packages/IPython/core/interactiveshell.py:2653, in InteractiveShell.system_piped(self, cmd) 2648 raise OSError("Background processes not supported.") 2650 # we explicitly do NOT return the subprocess status code, because 2651 # a non-None value would trigger :func:`sys.displayhook` calls. 2652 # Instead, we store the exit_code in user_ns. -> 2653 self.user_ns[&#39;_exit_code&#39;] = system(self.var_expand(cmd, depth=1)) File /lib/python3.12/site-packages/IPython/utils/_process_emscripten.py:11, in system(cmd) 10 def system(cmd): ---> 11 raise OSError("Not available") OSError: Not available
03-12
<think>嗯,用户遇到了一个OSError,错误信息示“Not available”,具体是在尝试用Jupyter Notebook运行%pip install pmdarima时出现的。首先,我需要分析错误的原因。 看报错的位置,是在IPython的_process_emscripten.py文件中,第11行的system函数抛出了这个错误。这提示可能是在Emscripten环境下运行,比如浏览器中的Python环境(如Pyodide),这些环境可能不支持子进程或系统命令的执行。因为%pip install通常会调用系统的pip命令,而在浏览器环境中,这类操作可能被限制,导致OSError。 接下来,用户的需求是安装pmdarima库,但当前的安装方式不可行。我需要考虑替代方法。可能的解决方法包括: 1. 检查运行环境:确认用户是否在使用在线Jupyter服务(如Google Colab、JupyterLite等)或本地环境。如果是线上环境,可能需要不同的安装方式。 2. 使用pip的替代命令:在Jupyter中,有时%%bash或!pip install可以绕过某些限制,但同样可能受环境限制。 3. 离线安装:如果在线安装不可行,可能需要下载whl文件手动安装,但这在浏览器环境中可能不可行。 4. 环境切换建议:如果用户在使用不支持pip的环境,建议切换到本地Python环境或支持pip的在线服务。 另外,需要确认pmdarima是否有其他依赖,比如scipy、statsmodels等,这些可能在受限环境中安装困难。如果用户确实在受限环境,可能需要寻找替代库或方法。 最后,整理回答步骤,先解释错误原因,再提供可能的解决方案,并给出具体操作示例,帮助用户逐步解决问题。</think>你的错误是由于在 **不支持系统命令执行的环境**(如浏览器中的Python环境或某些在线Jupyter平台)中尝试使用`%pip install`导致的。以下是逐步解决方法和解释: --- ### 错误原因 1. **环境限制**:你当前可能在使用 **Pyodide**(浏览器内Python环境)或 **JupyterLite**,这类环境无法直接调用系统命令(如`pip`)。 2. **IPython的`system`调用被阻止**:错误日志示`File /lib/python3.12/site-packages/IPython/utils/_process_emscripten.py`,表明代码运行在Emscripten编译的环境中(如浏览器),无法执行`pip install`。 --- ### 解决方案 #### 方法1:改用纯Python环境 **步骤**: 1. 本地安装Python(推荐[Miniconda](https://docs.conda.io/en/latest/miniconda.html)) 2. 在终端中直接运行: ```bash pip install pmdarima ``` 3. 启动本地Jupyter Notebook: ```bash jupyter notebook ``` #### 方法2:在线平台替代方案(如Google Colab) **步骤**: 1. 打开 [Google Colab](https://colab.research.google.com/) 2. 新建笔记本,直接运行: ```python !pip install pmdarima ``` (Colab支持`!`直接调用系统命令) #### 方法3:手动安装依赖(仅限支持的环境) 如果环境允许文件上传: 1. 下载`pmdarima`的whl文件:https://pypi.org/project/pmdarima/#files 2. 上传到环境并安装: ```python %pip install /path/to/pmdarima-2.0.4-cp312-cp312-manylinux_2_17_x86_64.whl ``` --- ### 附加说明 - **pmdarima的依赖**:该库依赖`numpy`, `scipy`, `statsmodels`等,若环境缺少这些库,需提前安装。 - **替代方案**:如果无法安装`pmdarima`,可尝试手动实现ARIMA模型(通过`statsmodels`库)。 --- ### 操作示例(Google Colab) ```python # 在Colab中运行 !pip install pmdarima # 使用!触发系统命令 # 验证安装 import pmdarima as pm print(pm.__version__) ``` --- 选择适合你当前环境的方法即可解决问题。如果仍有疑问,请说明你使用的具体平台(如JupyterLab、Pyodide等)!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值