中断/退出脚本


85

我有一个程序,可以进行一些数据分析,并且有数百行。

在程序的早期,我想进行一些质量控制,如果没有足够的数据,我希望程序终止并返回到R控制台。否则,我希望其余代码执行。

我已经尝试过breakbrowser和,quit并且它们都没有停止其余程序quit的执行(并且停止执行以及完全退出R,这不是我想发生的事情)。我的最后一招是创建如下if-else语句:

 if(n < 500){}
 else{*insert rest of program here*}

但这似乎是不好的编码习惯。我想念什么吗?


4
quit当然可以停止其余程序的执行。请提供一个可复制的示例
Joshua Ulrich

@JakeBurkhead-上面的代码(带有空的if语句)是最好的方法吗?@Joshua Ulrich,quit退出所有R,但是我想返回到R控制台,因为出于我的目的,程序需要保持打开状态。
user2588829 2013年

您所说的程序是什么意思?您是要运行自己编写的函数还是要采购脚本?
加文·辛普森

if-else可能是处理此问题的正确方法。如果一切使用正确,则不应该发生的情况除外。如果可能发生这种情况,并且您知道如何处理,请使用常规控制流程。
马修(马修)

Answers:


59

stopifnot()如果希望程序产生错误,可以使用该函数:

foo <- function(x) {
    stopifnot(x > 500)
    # rest of program
}

+1!我猜该函数foo应该称为脚本的开头,并包含其他验证控件...
agstudy 2013年

22
stopifnot很方便,但使用精心制作的响应if(x < 500) { stop("Not enough observations in 'x': n < 500")}可能会更可取。另外,如果这是批处理作业的内容,则在引发错误的情况下处理问题很有用。
加文·辛普森

4
停止尝试混淆OP。他想要的是quit()或stop(),而不是stopifnot()。
stackoverflowuser2010

10
@ stackoverflowuser2010他不希望quit(见问题!)我甚至不认为stopstopifnot是处理的最佳方式; stop引发错误,整个脚本将中止。尽管stopifnot(或stop)似乎是最受人欢迎的Answer OP,但编写一个无错误地干净退出的函数在更广泛的情况下更为有益。为大型数据分析工作编写了许多长时间运行的脚本,没有什么比抛出错误而不是处理问题并干净返回的函数更令人讨厌了。但显然我不知道我在说什么...
Gavin Simpson

能否请您澄清一下有关引发@GavinSimpson错误的评论?当我尝试时,stop("my message")我会被打印到终端上Error: "my message" Execution halted。因此,这将显示错误消息输出,但是您是说它不会“引发”错误吗?(即,如果它调用的任何脚本抛出错误,它将不会停止已设置为中止的批处理作业)。谢谢!(现在我正在用Rscript调用脚本)
rrr

13

不漂亮,但这是exit()在R中实现对我有用的命令的一种方法。

exit <- function() {
  .Internal(.invokeRestart(list(NULL, NULL), NULL))
}

print("this is the last message")
exit()
print("you should not see this")

仅经过轻微测试,但运行此命令时,我看到this is the last message脚本然后中止,没有任何错误消息。


缺点是不允许在CRAN软件包中使用代码。因此,如果您打算在要上载到CRAN的软件包中使用,它将在中显示警告R CMD CHECK
MS Berends

1
是的,这看起来更像是系统功能。如果更改解释器的内部详细信息,则可能会中断,因此,最好是R核心的一部分而不是放在单独的包中?通过在R源代码中遵循不同的路径,我发现如何在不发出错误消息的情况下最终到达正确的位置退出解释器,从而发现了这一点。我发现到达那里的方式并不多;这就是为什么我使用.invokeRestart它的原因,然后似乎又需要使用它.Internal
jochen

哦,是的,除了CRAN政策外,我认为这是一个不错的解决方案!让我为您提供+10代表;)
MS Berends 17-10-28

奇怪的。我刚刚尝试过,最后一条输出行是[1]“您应该看不到” R版本3.4.3(2017-11-30)平台:x86_64-pc-linux-gnu(64位)运行在:Red Hat下企业Linux服务器版本6.10(圣地亚哥)
CodingMatters

我刚刚尝试了@aspiringGuru,它仍然对我有用。您是否以脚本形式运行命令?如果您在命令行中一个接一个地运行它们(例如使用复制和粘贴),那么当然exit()不能阻止下一个命令(尚未输入)运行……
jochen

12

反转if-else的构造:

if(n >= 500) {
  # do stuff
}
# no need for else

2
很简单,我想这可能是我能做的最好的,谢谢
user2588829 2013年

9

编辑:看来OP运行长脚本,在这种情况下,一个只需要包裹脚本的一部分的质量控制

if (n >= 500) {

.... long running code here

}

如果要突破某个功能,您可能只想return()显式或隐式。

例如,明确的双重回报

foo <- function(x) {
  if(x < 10) {
    return(NA)
  } else {
    xx <- seq_len(x)
    xx <- cumsum(xx)
  }
  xx ## return(xx) is implied here
}

> foo(5)
[1] 0
> foo(10)
 [1]  1  3  6 10 15 21 28 36 45 55

return()是暗示,我的意思是,最后一行是因为如果你做了return(xx),但它会更有效呼叫离开关到return()

有些人认为使用多次返回很不好。在长函数中,跟踪函数的退出位置可能会变得困难或容易出错。因此,一种替代方法是具有单个返回点,但使用if () else ()子句更改返回对象。这样的修改foo()将是

foo <- function(x) {
  ## out is NA or cumsum(xx) depending on x
  out <- if(x < 10) {
    NA
  } else {
    xx <- seq_len(x)
    cumsum(xx)
  }
  out ## return(out) is implied here
}

> foo(5)
[1] NA
> foo(10)
 [1]  1  3  6 10 15 21 28 36 45 55

我也想到了这一点,但尚不清楚OP是否在谈论突破某个功能。
托马斯

是的,Thomas是对的-我不是在谈论打破功能。
user2588829 2013年

1
@ user2588829您最好将其作为函数而不是100+行脚本放在R中。
加文·辛普森

@GavinSimpson哦,我还是R的新手,所以我不知道。如果我将其定义为100+行函数,那是更好的做法吗?
user2588829 2013年

1
@ user2588829是的,更好。您可以控制函数的参数,以便可以传递所需的信息。而且,与其采购100多行代码来运行分析,您myFun(arg1, arg2, arg3)不如做其他事情。这只是组织事情的一种更好的方法。
加文·辛普森

9

也许您只是想在某个时候停止执行长脚本。即。就像您想用C或Python硬编码一个exit()一样。

print("this is the last message")
stop()
print("you should not see this")

1
对于此代码,我得到了错误消息Error in eval(expr, envir, enclos) :
jochen

2
是的,执行的确停止了。巧合的是,如果stop()exit()或替换please.stop.now(),脚本也会停止(仅错误消息当然有所不同)。
jochen

1
@jochen在stop()命令中添加带引号的短语可以帮助区分此“错误”与其他消息。例如:stop("Manual break inserted here")可能比stop()单独提供更多信息。
Omar Wasow

3

这是一个古老的问题,但是还没有一个干净的解决方案。这可能无法回答这个特定问题,但是那些寻求“如何从R脚本正常退出”答案的人可能会落在这里。R开发人员似乎忘记了实现exit()函数。无论如何,我发现的技巧是:

continue <- TRUE

tryCatch({
     # You do something here that needs to exit gracefully without error.
     ...

     # We now say bye-bye         
     stop("exit")

}, error = function(e) {
    if (e$message != "exit") {
        # Your error message goes here. E.g.
        stop(e)
    }

    continue <<-FALSE
})

if (continue) {
     # Your code continues here
     ...
}

cat("done.\n")

基本上,您使用标志来指示是否继续指定的代码块。然后,您可以使用该stop()函数将自定义消息传递给函数的错误处理程序tryCatch()。如果错误处理程序收到您要正常退出的消息,那么它将忽略该错误并将继续标记设置为FALSE


0

您可以使用“工具”包中的pskill函数R来中断当前进程并返回到控制台。具体而言,我在启动文件中定义了以下函数,该函数在每个脚本的开头提供。但是,您也可以在代码开头直接复制它。然后halt()在您的代码中的任意位置插入,以立即停止脚本执行。从GNU / Linux上来看,此功能运行良好,从R文档来看,它也应在Windows上运行(但我没有检查)。

# halt: interrupts the current R process; a short iddle time prevents R from
# outputting further results before the SIGINT (= Ctrl-C) signal is received 
halt <- function(hint = "Process stopped.\n") {
    writeLines(hint)
    require(tools, quietly = TRUE)
    processId <- Sys.getpid() 
    pskill(processId, SIGINT)
    iddleTime <- 1.00
    Sys.sleep(iddleTime)
}

> pskill(processId,SIGINT)关闭会话,甚至将用户踢出RStudio。这是非常危险的但起作用的..
Espanta 2015年

不知道它将使RStudio崩溃,但在以下文章中讨论了相同的问题:stackoverflow.com/questions/32820534/…尽管在linux上,我的解决方案仍然可以正常工作。与stopifnot相比,它的优点是不会显示stopifnot()错误消息。
弗朗索瓦·唐纳

我在Windows上检查了一下,发现它表现得很疯狂。不管怎么说,还是要谢谢你。我喜欢pskill。
Espanta

0

这里:

if(n < 500)
{
    # quit()
    # or 
    # stop("this is some message")
}
else
{
    *insert rest of program here*
}

两者quit()stop(message)都会退出您的脚本。如果您是从R命令提示符处采购脚本的,则该脚本quit()也会从R退出。


7
发布与已经发布的答案重复的答案是错误的做法。
托马斯

@Thomas此答案重复哪个?我只看到了同时使用停止和退出的答案,并实际上解释了它们之间的区别。

@托马斯:确切说明我的答案重复了什么答案。
stackoverflowuser2010

@托马斯:我对你的批评提出了一个问题。我在等你来回答。
stackoverflowuser2010

5
@netskink的答案使用stop(),OP已在注释中指示他们不想要quit()...
Ben Bolker
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.