Skript unterbrechen / beenden

84

Ich habe ein Programm, das einige Datenanalysen durchführt und einige hundert Zeilen lang ist.

Sehr früh im Programm möchte ich eine Qualitätskontrolle durchführen. Wenn nicht genügend Daten vorhanden sind, soll das Programm beendet werden und zur R-Konsole zurückkehren. Ansonsten möchte ich, dass der Rest des Codes ausgeführt wird.

Ich habe versucht break, browserund quitkeiner von ihnen die Ausführung der Rest des Programms stoppen (und quitstoppt die Ausführung sowie vollständig beenden R, die nicht etwas , was ich passieren soll , ist). Mein letzter Ausweg ist die Erstellung einer if-elseErklärung wie folgt :

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

aber das scheint eine schlechte Codierungspraxis zu sein. Vermisse ich etwas

user2588829
quelle
4
quitstoppt mit Sicherheit die Ausführung des restlichen Programms. Bitte geben Sie ein reproduzierbares Beispiel an .
Joshua Ulrich
@JakeBurkhead - ist mein Code oben (mit einer leeren if-Anweisung) der beste Weg? @ Joshua Ulrich, beendet quitalle R, aber ich möchte zur R-Konsole zurückkehren, da das Programm für meine Zwecke geöffnet bleiben muss.
user2588829
Was meinst du mit einem Programm? Meinen Sie damit, dass Sie eine von Ihnen geschriebene Funktion ausführen oder in einem Skript suchen?
Gavin Simpson
if-else ist wahrscheinlich der richtige Weg, um damit umzugehen. Ausnahmen sind Situationen, die nicht auftreten sollten, wenn alles richtig verwendet wird. Wenn dies passieren kann und Sie wissen, wie Sie damit umgehen sollen, verwenden Sie den normalen Kontrollfluss.
Matthew

Antworten:

60

Sie können die stopifnot()Funktion verwenden, wenn das Programm einen Fehler erzeugen soll:

foo <- function(x) {
    stopifnot(x > 500)
    # rest of program
}
Michael Malick
quelle
+1! Ich denke, die Funktion foosollte der Anfang des Skripts genannt werden und andere Validierungskontrollen enthalten ...
Agstudy
22
stopifnotist praktisch, aber eine gestaltete Antwort mit if(x < 500) { stop("Not enough observations in 'x': n < 500")}könnte bevorzugt werden. Wenn dies für einen Stapeljob gilt, ist es hilfreich , das Problem zu behandeln, ohne einen Fehler auszulösen.
Gavin Simpson
4
Hör auf zu versuchen, das OP zu verwirren. Was er will, ist quit () oder stop (), nicht stopifnot ().
stackoverflowuser2010
10
@ stackoverflowuser2010 Er will nicht quit(siehe Frage!) Ich glaube , nicht einmal stopder stopifnotist der beste Weg , dies zu handhaben ; stopWenn ein Fehler ausgegeben wird, wird das gesamte Skript einfach abgebrochen. Während stopifnot(oder stop) die Antwort zu sein scheint, die OP am besten gefällt, ist das Schreiben einer Funktion zum sauberen und fehlerfreien Beenden in einer größeren Anzahl von Situationen vorteilhafter. Nachdem Sie viele lang laufende Skripte für große Datenanalysejobs geschrieben haben, ist nichts ärgerlicher als Funktionen, die Fehler auslösen, anstatt das Problem zu behandeln und sauber zurückzukehren. Aber klar, ich weiß nicht, wovon ich spreche ...
Gavin Simpson
Können Sie bitte Ihren Kommentar zum Auslösen eines Fehlers @GavinSimpson klarstellen? Wenn ich es versuche, werde stop("my message")ich in das Terminal gedruckt Error: "my message" Execution halted. Dies zeigt also eine Ausgabe einer Fehlermeldung, aber sagen Sie, dass sie keinen Fehler "auslöst"? (dh es wird kein Stapeljob gestoppt, der so eingestellt wurde, dass er abgebrochen wird, wenn eines der aufgerufenen Skripte Fehler auslöst). Vielen Dank! (Im Moment rufe ich das Skript mit Rscript auf)
rrr
14

Nicht schön, aber hier ist eine Möglichkeit, einen exit()Befehl in R zu implementieren, der für mich funktioniert.

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

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

Nur leicht getestet, aber wenn ich dies ausführe, sehe ich this is the last messageund dann bricht das Skript ohne Fehlermeldung ab.

jochen
quelle
Nachteil ist, dass Code in einem CRAN-Paket nicht zulässig ist. Wenn Sie also beabsichtigen, es in einem Paket zu verwenden, das Sie in CRAN hochladen möchten, wird eine Warnung in der angezeigt R CMD CHECK.
MS Berends
1
Ja, das sieht eher nach einer Systemfunktion aus. Es könnte kaputt gehen, wenn interne Details des Interpreters geändert werden. Ist es also besser, ein Teil des R-Kerns zu sein, als in einem separaten Paket? Ich fand dies, indem ich verschiedenen Pfaden durch den R-Quellcode folgte, um zu sehen, wie ich an der richtigen Stelle landen konnte, um den Interpreter zu verlassen, ohne dass eine Fehlermeldung ausgegeben wurde. Es gab nicht so viele Möglichkeiten, dorthin zu gelangen. deshalb benutze ich .invokeRestartwas dann wiederum das zu brauchen scheint.Internal .
Jochen
Oh ja, abgesehen von den CRAN-Richtlinien halte ich es für eine gute Lösung! Lassen Sie mich Ihnen eine +10 Wiederholung liefern;)
MS Berends
seltsam. Ich habe es gerade versucht und die letzte Ausgabezeile war [1] "Sie sollten diese nicht sehen" R Version 3.4.3 (2017-11-30) Plattform: x86_64-pc-linux-gnu (64-Bit) Läuft unter: Red Hat Enterprise Linux Server Version 6.10 (Santiago)
CodingMatters
@aspiringGuru Ich habe es gerade versucht und es funktioniert immer noch für mich. Haben Sie die Befehle als Skript ausgeführt? Wenn Sie sie nacheinander in der Befehlszeile ausführen ( z durch Kopieren und Einfügen), exit()kann dies natürlich nicht verhindern, dass der nächste Befehl (der noch nicht eingegeben wurde) ausgeführt wird ...
jochen
13

Kehren Sie Ihre if-else-Konstruktion um:

if(n >= 500) {
  # do stuff
}
# no need for else
Thomas
quelle
2
einfach genug und ich denke, dies könnte das Beste sein, was ich tun kann, danke
user2588829
10

Vielleicht möchten Sie irgendwann einfach aufhören, ein langes Skript auszuführen. dh. Als ob Sie ein exit () in C oder Python hart codieren möchten.

print("this is the last message")
stop()
print("you should not see this")
Netskink
quelle
1
Für diesen Code erhalte ich die Fehlermeldung Error in eval(expr, envir, enclos) :.
Jochen
2
Ja, die Ausführung hört tatsächlich auf. Zufälligerweise , wenn Sie ersetzen stop()mit exit()oder please.stop.now()das Skript stoppt auch (nur die Fehlermeldungen sind natürlich unterschiedlich).
Jochen
1
@jochen Das Hinzufügen einer zitierten Phrase innerhalb des stop()Befehls kann dazu beitragen, diesen "Fehler" von anderen Nachrichten zu unterscheiden. Zum Beispiel: stop("Manual break inserted here")könnte informativer sein als stop()allein.
Omar Wasow
9

Bearbeiten: Scheint, dass das OP ein langes Skript ausführt. In diesem Fall muss nur der Teil des Skripts nach der Qualitätskontrolle mit umbrochen werden

if (n >= 500) {

.... long running code here

}

Wenn Sie aus einer Funktion ausbrechen möchten Sie wahrscheinlich nur return()explizit oder implizit.

Zum Beispiel eine explizite doppelte Rückgabe

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

Mit return()impliziert meine ich, dass die letzte Zeile so ist, als ob Sie es getan hätten return(xx), aber es ist etwas effizienter, den Anruf an abzubrechenreturn() .

Einige erwägen, einen schlechten Stil für mehrere Rückgaben zu verwenden. Bei langen Funktionen kann es schwierig oder fehleranfällig werden, zu verfolgen, wo die Funktion beendet wird. Daher besteht eine Alternative darin, einen einzelnen Rückgabepunkt zu haben, das Rückgabeobjekt jedoch mithilfe der if () else ()Klausel zu ändern . Eine solche Änderung foo()wäre

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
Gavin Simpson
quelle
Ich habe auch darüber nachgedacht, aber es ist nicht klar, dass OP davon spricht, aus einer Funktion auszubrechen.
Thomas
Ja, Thomas hat recht - ich spreche nicht davon, aus einer Funktion auszubrechen.
user2588829
1
@ user2588829 Es wäre viel besser, wenn Sie dies als Funktion in R einfügen würden, als als Skript mit mehr als 100 Zeilen.
Gavin Simpson
@ GavinSimpson Oh, ich bin noch neu bei R, also wusste ich das nicht. Wenn ich es als 100+ Linienfunktion definiere, ist das eine bessere Praxis?
user2588829
1
@ user2588829 Ja, viel besser. Sie steuern die Argumente der Funktion, damit Sie die erforderlichen Informationen übergeben können. Anstatt mehr als 100 Codezeilen für die Ausführung der Analyse zu verwenden, myFun(arg1, arg2, arg3)ist dies eine viel bessere Möglichkeit, Dinge zu organisieren.
Gavin Simpson
3

Dies ist eine alte Frage, aber es gibt noch keine saubere Lösung. Dies beantwortet wahrscheinlich nicht diese spezielle Frage, aber diejenigen, die nach Antworten suchen, wie man ein R-Skript ordnungsgemäß verlässt, werden wahrscheinlich hier landen. Es scheint, dass R-Entwickler vergessen haben, eine exit () -Funktion zu implementieren. Der Trick, den ich gefunden habe, ist:

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")

Grundsätzlich verwenden Sie ein Flag, um die Fortsetzung eines bestimmten Codeblocks anzuzeigen oder nicht. Anschließend verwenden Sie die stop()Funktion, um eine benutzerdefinierte Nachricht an den Fehlerbehandler einer tryCatch()Funktion zu übergeben. Wenn der Fehlerbehandler Ihre Nachricht zum ordnungsgemäßen Beenden erhält, ignoriert er den Fehler einfach und setzt das Fortsetzungsflag auf FALSE.

user2641103
quelle
1

Mit der pskillFunktion im RPaket "tools" können Sie den aktuellen Prozess unterbrechen und zur Konsole zurückkehren. Konkret habe ich die folgende Funktion in einer Startdatei definiert, die ich am Anfang jedes Skripts beziehe. Sie können es jedoch auch direkt am Anfang Ihres Codes kopieren. Fügen Sie dann halt()an einer beliebigen Stelle in Ihren Code ein, um die Skriptausführung im laufenden Betrieb zu stoppen. Diese Funktion funktioniert gut unter GNU / Linux und nach der RDokumentation sollte sie auch unter Windows funktionieren (aber ich habe es nicht überprüft).

# 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)
}
François Tonneau
quelle
> pskill (processId, SIGINT) schließt die Sitzung und wirft den Benutzer sogar aus RStudio heraus. Es ist ziemlich gefährlich, aber funktionsfähig ....
Espanta
Ich wusste nicht, dass RStudio abstürzen würde, aber das gleiche Problem wird in Stackoverflow.com/questions/32820534/… unter Linux behandelt. Meine Lösung funktioniert jedoch einwandfrei . Der Vorteil gegenüber stopifnot besteht darin, dass die Fehlermeldung stopifnot () nicht angezeigt wird.
François Tonneau
Ich habe Windows überprüft und es verhält sich verrückt. Danke trotzdem. Ich mag die Fähigkeit.
Espanta
0

Hier:

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

Beides quit()und stop(message)wird Ihr Skript beenden. Wenn Sie Ihr Skript über die R-Eingabeaufforderung beziehen, quit()wird R ebenfalls beendet.

stackoverflowuser2010
quelle
7
Es ist eine schlechte Praxis, Antworten zu veröffentlichen, die die bereits veröffentlichten Antworten duplizieren.
Thomas
@ Thomas welche Antwort dupliziert das? Ich sehe nur diese Antwort, indem ich sowohl stop als auch quit verwende und tatsächlich den Unterschied zwischen ihnen erkläre.
@Thomas: Erkläre genau, welche Antwort meine Antwort dupliziert.
stackoverflowuser2010
@ Thomas: Ich habe eine Frage zu Ihrer Kritik gestellt. Ich warte darauf, dass Sie es beantworten.
stackoverflowuser2010
5
@ Netskink Antwort verwendet stop(), und OP bereits in Kommentaren angegeben, dass sie nicht wollen quit()...
Ben Bolker