R: system()无法使用在.bashrc中定义的bash函数。

5

问题

我的默认Python版本是2.7,但我有一个需要Python 3.4的脚本。我正在尝试创建一个R函数来:

  1. 切换至Python 3.4
  2. 运行这个脚本
  3. 切换回Python 2.7
  4. 将结果导入R中

为了在Python版本之间进行切换,我使用了我的集群的“dotkit”系统,如下所示:

use Python-2.7
use Python-3.4

"use"是一个bash函数,被导入到我的.bashrc文件中。它设置了所有的路径变量(PATH、LIBRARY_PATH、LD_LIBRARY_PATH、CPATH、C_INCLUDE_PATH等)。问题在于,当我尝试在R中调用这个函数时,会出现以下错误:

system('use Python-3.4')
sh: use: command not found

看起来这是我的 PATH 的问题。我正在使用正确的 shell:

system('echo $SHELL')
/bin/bash

我的$PATH变量看起来也很好。然而,当我创建一个基本上做同样事情的脚本时:

load_py34.sh:

#!/bin/bash
source ~/.bashrc
use Python-3.4

通过R调用此脚本后,实际运行了,但出于某种原因,在R中并没有更改我的Python版本。(我已验证此脚本可以从命令行正常工作。)
> R
> system('python --version')
Python 2.7.1
> system('sh load_py34.sh')
Prepending: R-3.4 (ok)
> system('python --version')
Python 2.7.1

我有点困惑,但如果有人能帮忙,我会非常感激。


建议的修复方法

当我将它们组合成一个命令时,仍然存在相同的问题:

> system("sh load_py34.sh; python --version")
Prepending: Python-3.4 (already loaded)
Python 2.7.1

当我尝试直接调用bash时,PATH仍然存在问题:

> system("bash -c 'use Python-3.4; python --version'")
bash: use: command not found
Python 2.7.1

当我将它们组合成一个单独的调用时,我会得到相同的错误。我会更新问题以反映这一点。 - adn bps
2个回答

3

.bashrc 仅为交互式 bash 会话加载。

"use" 是一个被导入到我的 .bashrc 文件的 bash 函数,它设置了所有的路径变量。

如果通过 export 设置,调用进程的环境将不会被改变。

export [-fn] [name[=word]] ... 提供的名称会自动导出到随后执行的命令的环境中。(https://man7.org/linux/man-pages/man1/bash.1.html)

子进程通常无法访问父进程的环境。(这是一个问题,因为system()会创建一个子进程。)

source. 内置命令在当前 shell 环境中执行命令,这就是你的脚本能工作的原因。

其他命令(可执行文件、非 shell 内置命令)通过“fork-and-exec”机制执行,即执行的 shell 进程分叉,创建一个具有相同环境和状态的子进程。这个新的子进程是执行命令的进程。对该进程环境的更改不会复制到父环境中。

这意味着你将无法依赖于 system('...') 来修改 R 进程的环境,或者在后续的 system() 调用中生成的进程的环境。

在单个对 system() 的调用中,可以构造一个命令行以更改派生 shell 的环境,如下所示:

bash -c 'source ~/.bashrc; use Python-3.4; python --version'

请注意,将此功能放在~/.bashrc并不是最好的做法(可能是主观的)。


0

当你调用system()时,它使用的是/bin/sh而不是/bin/bashsh在启动时不会读取你的.bashrc文件,因此它不知道你在那里定义的任何函数。

要使用来自你的.bashrc的函数,你必须让bash来运行它:

system("bash -c 'use Python-3.4; python --version'")

编辑:单引号的关闭位置。


这给了我相同的错误(请参见更新的问题)。 - adn bps

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接