【问题标题】:Permission denied when calling subprocess.call(['.', bash_path])调用 subprocess.call(['.', bash_path]) 时权限被拒绝
【发布时间】:2020-08-25 21:19:36
【问题描述】:

当我运行以下代码时

import os
import subprocess

bash_path = os.path.expanduser('~/.bash_profile')
subprocess.call(['.',  bash_path])

我收到以下错误:

Traceback (most recent call last):
  File "/path/to/my/script/my_script.py", line 4, in my_func
    subprocess.call(['.',  bash_path])
  File "/Users/user/miniconda3/envs/live_auction/lib/python3.7/subprocess.py", line 323, in call
    with Popen(*popenargs, **kwargs) as p:
  File "/Users/jisom/miniconda3/envs/live_auction/lib/python3.7/subprocess.py", line 775, in __init__
    restore_signals, start_new_session)
  File "/Users/jisom/miniconda3/envs/live_auction/lib/python3.7/subprocess.py", line 1522, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
PermissionError: [Errno 13] Permission denied: '.'

我也尝试了subprocess.call(['source', bash_path]) 的变体,但用source 替换. 得到了相同的结果。从 python 脚本看来,我没有权限调用 source.,但我可以从我的终端调用。

我正在尝试重新加载我的环境变量,因为我的程序在此之前调用了另一个子进程来更新一些配置变量,但是,在我重新source 或重新启动终端之前,它们不可用。

如何在 python 脚本中重新source 我的.bash_profile

【问题讨论】:

  • .source 是 shell 内置函数;它们不是单独的可执行程序。
  • 在 bash cli 上,你是否为你的 python 文件添加了执行权限? sudo chmod +x myscript.py

标签: python bash subprocess chmod


【解决方案1】:

这里有两个问题:

  1. .(及其别名source)不是execv(或Python 中的subprocess)可以执行的程序。它们是 shell 内置的。

  2. 并非巧合,. 不能由外部程序实现,这就是它内置在 shell 中的原因。

第一个解释了为什么不能使用subprocess.call 来执行.sourcesubprocess.call 只能执行外部程序。它不能执行内置的shell,因为没有shell; subprocess.call 在 Python 程序中运行,而不是在 shell 中。因此,当您尝试subprocess.call('.',...) 时,您正在尝试执行.,这是一个目录。说您没有运行目录的权限在技术上是正确的,但作为错误消息并不是很有用;即使是 root 用户也无法执行目录。我希望subprocess.call(['source', ...]) 会产生“没有这样的文件或目录”错误,但也许您在执行路径的某处有一个名为source 的文件(没有执行权限)。 (不是一个好主意,因为source 通常用作内置的shell。)

但真正关键的是第二个问题。一个外部程序,即使是一个小时候运行的程序,也无法进入 Python 正在运行的进程并追溯更改进程环境变量。 (或者,就此而言,当前工作目录,这就是为什么你不能subprocess.call cd 命令。)

环境变量之所以被称为是因为它们是执行环境的一部分。执行环境是与进程一起创建的,或者说进程的一部分是执行环境可能会更好。大多数执行环境都是从父进程继承的。但这并不意味着一个进程与它的子进程共享它的环境。相反,该进程将其环境复制到为孩子创建的新环境中。所以环境变量是从parent传给child的,但是child的变量是它自己的自变量;更改它们不会影响父级的环境变量,也不会影响其已经生成的子级的环境变量。

当您启动一个新的“登录 shell”(这是与操作系统协商以允许您登录的进程)时,该 shell 会执行您的配置文件脚本,该脚本会自定义 shell 的执行环境。 (如果你的 shell 是 bash,它将使用特定于 bash 的配置文件 ~/.bash_profile 脚本,如果它存在的话。)从那里,新创建的那个 shell 的子进程——包括你启动的所有其他进程,包括图形控制台会话 -- 使用此执行环境的副本启动。

配置文件脚本的执行必须使用.(或等效项)来完成,因为其目的是改变当前的执行环境。 . 可以做到这一点,因为它是一个 bash 命令,而不是在子进程中运行的外部命令。它只是执行给定脚本中的每个 shell 命令,就好像您直接键入它一样,因此它发生在当前执行环境中。但是 Python 没有任何等价物。 Python 不是 bash shell,它不知道任何 bash 命令行是什么意思。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-05
    • 2015-08-30
    • 2013-12-14
    • 1970-01-01
    • 1970-01-01
    • 2014-10-04
    相关资源
    最近更新 更多