R脚本如何检测它是否被另一个脚本调用或引用

13

我写了一个脚本,当它被调用时会检查脚本是否以交互方式运行,使用 interactive() 进行检查。如果它是以交互方式运行的,则不会搜索命令行参数。然而,如果它不是以交互方式运行,它将搜索命令行参数并抛出错误。

通常情况下这没问题,但有时我会编写第二个 R 脚本,只是为了处理一些数据。所以 Script2 源代码中导入 Script1,而 Script1 检测到它不是以交互方式运行,并开始搜索命令行参数并抛出错误。

除了 interactive() 之外,脚本还能以其他方式检测上下文吗?例如,当直接运行脚本时,我希望有不同的行为与当加载其内部函数访问时。对于包,我可以像这样使用 dplyr :: arrange() 访问 arrange,而无需加载所有 dplyr。

编辑:我的当前非常拙劣的解决方法是启动一个交互式会话,源代码中导入 Script1,使用 save.image() 来保存函数,然后在 Script2 中使用 load 加载保存的 .RData 文件。但显然这不是...优雅的方法。


我认为我使用的确切代码并不那么重要,但如果有人觉得这对答案很重要,我会包括在内...

精简示例代码:

#!/usr/bin/env Rscript

library(optparse)

function1 <- function(etc,etc) {}
function2 <- function(etc,etc) {}

if(!interactive()) { 

    # example call
    # Rscript create_reference_file.R -c cd4cd8 -o /home/outputfolder/ 

    option_list = list(
        make_option(c('-c', '--cell'), type = 'character', default = NULL,
                    help = 'the name of the cell',
                    metavar = 'character'),
        make_option(c('-o','--outdir'), type = 'character', default = NULL, 
                    help = 'the location where you wish to store your output',
                    metavar = 'character'),
    )

    opt_parser <- OptionParser(option_list = option_list)
    opt <- parse_args(opt_parser)

    function1(opt); function2(opt) # etc etc, I do stuff with the opt inputs
}

4
你是在寻找类似于Python中的 if __name__ == '__main__': 这样的东西,对吗? - r2evans
如果你不懂Python,这里有一些关于那个引用的背景信息:https://dev59.com/bHRC5IYBdhLWcg3wD87r - r2evans
是的!那基本上就是我正在寻找的相同功能(或者能够实现类似结果的东西)。 - Brandon
1个回答

23

编辑

好的,这更像是 Python 的__name__技巧。 (下面是以前的回答,仅供参考。)

function1 <- function(etc,etc) {}
function2 <- function(etc,etc) {}

if (sys.nframe() == 0L) {
    library(optparse)
    # ...
}

这个方法非常简洁,而且无需调用脚本了解任何信息,即使在嵌套时也能很好地工作。

其他可能的机制可以使用(需要额外的函数),通过查看脚本名称,参考Rscript:确定正在执行的脚本的路径。 那里存在许多可行的(一些真正好的)解决方案,但它们都需要预定义的函数未在基础包中定义(或包含在要源化的脚本中的非平凡代码)。 如果您想“假设安装了X软件包”,那么您的脚本就有可能不可移植。


(前面的回答,我建议您使用上面的方法。)

我提出这个技巧…它只比您的解决方法稍微好一点,但它依赖于调用脚本知道被调用的脚本正在测试什么。

如果调用脚本设置一个变量:

BEING_SOURCED_FROM_SOMEWHERE <- TRUE

然后被调用的脚本可以检查它:

function1 <- function(etc,etc) {}
function2 <- function(etc,etc) {}

if (! exists("BEING_SOURCED_FROM_SOMEWHERE")) {
  library(optparse)
  # ...
}

我不喜欢它。它没有Python灵活。

if __name__ == "__main__":
    import optparse
    # ...

但是我认为我对此不太反感,相比你在函数定义中使用 saveload


也许@DirkEddelbuettel在littler工具中有相关内容? - r2evans
2
@Brandon,我认为我的编辑包含了你正在寻找的优美解决方案。 - r2evans
2
小建议:为了方便后来者,请编辑您的答案,使您使用sys.nframe的极简和优雅的编辑排在第一位... - malcook
1
当想要将在R Studio中“获取”文件视为运行脚本时,我不得不编辑条件为if ( if(!is.na(Sys.getenv("RSTUDIO", unset = NA))) sys.nframe() == 4L else sys.nframe() == 0L) { # interactive code here }。虽然有些混乱和hacky,但对我来说有效。 - Josiah Yoder
1
我不知道这个(我不使用RStudio IDE),谢谢!也许可以进行一些代码高尔夫:if (sys.nframe() == (4L * (!is.na(Sys.getenv("RSTUDIO", unset = NA))))) {...} - r2evans
显示剩余3条评论

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