问题描述
当我运行以下代码时
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
)不是可由execv
(或Python中的subprocess
)执行的程序。它们是Shell内置的。 -
并非巧合的是,
.
不能由外部程序实现,这就是为什么它内置于shell中的原因。
第一个解释了为什么不能使用subprocess.call
执行.
或source
的原因。 subprocess.call
只能执行外部程序。它无法执行内置的Shell,因为没有Shell。 subprocess.call
在Python程序而非外壳程序中运行。因此,当您尝试subprocess.call('.',...)
时,您尝试执行的是目录.
。说您没有运行目录的权限在技术上是正确的,但作为错误消息不是很有用;目录,即使由root用户也无法执行。我希望subprocess.call(['source',...])
会产生“没有这样的文件或目录”错误,但是也许您的执行路径中某处有一个名为source
的文件(没有执行权限)。 (这不是一个好主意,因为source
通常用作内置的Shell。)
但这实际上是第二个关键问题。一个外部程序,甚至是一个以子程序运行的程序,都无法进入运行Python的进程,并且无法追溯地更改进程环境变量。 (或者,就此而言,是当前的工作目录,这就是为什么您无法subprocess.call
cd
命令的原因。)
环境变量之所以被称为是因为它们是执行环境的一部分。执行环境是与流程一起创建的,或者也许最好说流程的一部分是执行环境。大多数执行环境是从流程父级继承的。但这并不意味着进程与其子环境共享。而是,进程将其环境复制到为孩子创建的新环境中。因此,环境变量是从父级传递到子级的,但是子级的变量是其自己的独立变量;对其进行更改不会影响父级的环境变量,也不会影响其已经产生的子级的环境变量。
当启动新的“登录外壳”(与操作系统协商以允许您登录的过程)时,该外壳将执行配置文件脚本,该脚本将自定义外壳的执行环境。 (如果您的外壳程序是bash
,它将使用bash特定的配置文件~/.bash_profile
脚本(如果存在)。)从那以后,该外壳程序的新创建的子进程-包括您的所有其他进程开始,包括图形控制台会话-从此执行环境的副本开始。
必须使用.
(或等效命令)执行配置文件脚本,因为目的是更改当前的执行环境。 .
可以做到这一点,因为它是bash命令,而不是在子进程中运行的外部命令。它只是在给定脚本中执行每个shell命令,就像您直接键入它一样,因此它发生在当前执行环境中。但是Python没有任何等效项。 Python不是bash shell,也不知道bash命令行的含义。