在从Python subprocess.Popen()调用的脚本中模拟shell命令

时间:2016-06-21 19:36:40

标签: python bash shell subprocess

我有一种情况,我需要使用我编写的shell脚本(mock_pip)来模拟可执行文件(pip)以进行单元测试,因此我使用子进程模块来访问shell。我尝试了很多类似的事情:

subprocess.Popen("alias pip='/some/dir/mock_pip'", shell=True) # Create alias
subprocess.Popen("pip", shell=True) # Try to use new alias, but still points towards real pip instead

subprocess.Popen("alias pip='/some/dir/mock_pip'"; "pip", shell=True)
# Once again it uses the real pip instead of mock

我甚至通过更改主目录中的~/.bashrc文件(也在使用子流程进行单元测试期间)尝试了此method,但这也不起作用。
我想象的问题是,在调用每个命令之后,子进程会擦除环境,这意味着当我尝试调用它时,我的别名不存在。

如何在从Python进程启动的bash脚本中使用mock_pip代替pip

1 个答案:

答案 0 :(得分:2)

如果你的目标是提供pip的模拟实现,你可以通过以下几种方式实现:

  • 将其生成为导出功能
  • 将指向包含包装器的目录的PATH值设置为可执行脚本

前者是特定于shell版本的,因此我们将首先介绍后者:

subprocess.Popen('pip', env={'PATH': '/path/to/mock/dir:' + os.environ['PATH']})

...您的/path/to/mock/dir是一个位置,其pip可执行文件可执行您所需的操作。

后者,用于post-shellshock上游bash版本(以及之前版本的bash,其shellshock修复程序与上游到达的导出函数的协议兼容):

env = dict(os.environ)
env['BASH_FUNC_pip%%'] = '() { mock_pip "$@"; }'
subprocess.Popen(['bash', '-c', 'pip'], shell=False, env=env)

请注意shell=False此处带有明确的['bash', '-c', ...] - 确保它是bash(它将尊重导出的函数),而不是默认的shell sh被调用