Unix-Befehl, der sofort einen bestimmten Rückkehrcode zurückgibt?

28

Gibt es einen Standard-Unix-Befehl, der ähnlich wie im folgenden Beispiel funktioniert?

$ <cmd here> 56
$ echo Return code was $?
Return code was 56
$

<cmd here>sollte etwas sein, das vom Fork ausgeführt werden kann und beim Beenden des Prozesses 56 als Exit-Code belässt. Die exitund returnShell Builtins sind für das, wonach ich suche, ungeeignet, da sie die aufrufende Shell selbst beeinflussen, indem sie sie verlassen. <some cmd>sollte etwas sein, das ich in Nicht-Shell-Kontexten ausführen kann - z. B. über ein Python-Skript mit aufrufen subprocess.

ZB wird /usr/bin/falseimmer sofort mit dem Rückkehrcode 1 beendet, aber ich möchte genau steuern, was dieser Rückkehrcode ist. Ich könnte die gleichen Ergebnisse erzielen, indem ich mein eigenes Wrapper-Skript schreibe

$ cat my-wrapper-script.sh # i.e., <some cmd> = ./my-wrapper-script.sh
#!/usr/bin/bash
exit $1
$ ./my-wrapper-script.sh 56
$ echo $?
56

Ich hoffe jedoch, dass es einen Standard-Unix-Befehl gibt, der dies für mich erledigen kann.

Chris
quelle
10
exitist die einzige, an die ich denken kann, aber es neigt dazu, deine Muschel zu beenden. bash -c 'exit 56'oder bash -c "exit $1"könnte für Sie arbeiten.
Tim Kennedy
12
Wie wäre es (exit 56)?
Cuonglm
6
Das klingt wirklich wie ein XYProblem : Was ist das ultimative Ziel davon? Warum brauchen Sie einen Befehl, der die von Ihnen angegebene Nummer als Exit-Code zurückgibt?
Olivier Dulac
1
Nun, Sie haben die trueund falseeingebauten, wenn Sie 0 oder 1 zurückgeben müssen.
gardenhead
1
verwandt: (nicht portierbares) kleinstes Programm, um einen festen Wert zur Kompilierungszeit zurückzugeben: muppetlabs.com/~breadbox/software/tiny/teensy.html
Florian Castellane

Antworten:

39
  1. Eine returnbasierende Funktion würde funktionieren und das Öffnen und Schließen einer anderen Shell vermeiden (laut Tim Kennedys Kommentar ):

    freturn() { return "$1" ; } 
    freturn 56 ; echo $?

    Ausgabe:

    56
  2. Verwenden exitin einer Unterschale:

    (exit 56)

    Bei anderen Schalen bedeutet dies ksh93, dass ein zusätzlicher Prozess erforderlich ist, der weniger effizient ist als der oben beschriebene.

  3. bash/ zsh/ ksh93Nur Trick:

    . <( echo return 56 )

    (das impliziert auch einen zusätzlichen Prozess (und IPC mit einer Pipe)).

  4. zshLambda-Funktionen von:

    (){return 56}
agc
quelle
Guter Gedanke. Leider war meine ursprüngliche Frage nicht gut genug definiert - das "Öffnen und Schließen einer anderen Shell" war fast eine Voraussetzung für das, was ich tun wollte. Ich habe meine Frage bearbeitet, um zu fordern, dass dies <some cmd>eine ausführbare () - fähige Sache ist.
Chris
2
@ Chris: Für jede Shell - Befehl können Sie es () in der Lage machen execve indem sie sie zu konvertieren/bin/sh -c ...originalcommand...
psmears
3
Ich bin leicht enttäuscht, dass? = 56 nicht funktioniert.
Joshua
@Joshua: vielleicht doch? aber dann war diese affektion erfolgreich, und du hast $? set to 0 ...;)
Olivier Dulac
@OlivierDulac: Das tut es nicht. Es gibt einen Analysefehler aus.
Joshua
17

Es gibt keinen Standard-UNIX-Befehl, um nur einen bestimmten Wert zurückzugeben. Die GNU Core Utilies bieten trueund falsenur.

Sie können dies jedoch problemlos selbst implementieren als ret:

#include <stdlib.h>
int main(int argc, char *argv[]) {
  return argc > 1 ? atoi(argv[1]) : 0;
}

Kompilieren:

cc ret.c -o ret

Und Renn:

./ret 56 ; echo $?

Drucke:

56

Wenn dies überall funktionieren soll (wo bash verfügbar ist), ohne zusätzliche Tools zu installieren, müssen Sie wahrscheinlich den folgenden Befehl verwenden, wie in den Kommentaren von @TimKennedy vorgeschlagen:

bash -c 'exit 56'

Beachten Sie, dass der gültige Bereich der Rückgabewerte 0..255 ist .

tmh
quelle
1
trueund falsesind auch in Unix (und sogar POSIX), nicht nur in GNU.
Stéphane Chazelas
@ StéphaneChazelas Danke für den Hinweis. Wie das OP erwähnte, habe ich GNU angenommen - obwohl die Frage selbst 'Unix' lautet.
10.
14

Wenn Sie den Exit-Status durch einen ausgeführten Befehl setzen möchten. Es gibt keinen dedizierten Befehl für diese 1 , aber Sie können den Interpreter jeder Sprache verwenden, die die Fähigkeit hat, mit einem beliebigen Beendigungsstatus zu beenden. shist das offensichtlichste:

sh -c 'exit 56'

Bei den meisten shImplementierungen ist dies auf die Beendigungscodes 0 bis 255 beschränkt ( shakzeptiert höhere Werte, schneidet sie jedoch möglicherweise ab oder bewirkt sogar, dass ein Signal an den Prozess gesendet wird, der shwie bei ksh93 für die Codes 257 bis 320 ausgeführt wird).

Ein Exit-Code kann ein beliebiger Integer ( int) - Wert sein. Beachten Sie jedoch, dass Sie ihn mit der waitid()Schnittstelle abrufen müssen, damit der Wert nicht auf 8 Bit gekürzt wird (unter Linux wird er jedoch auch weiterhin gekürzt waitid()). Daher ist es selten (und keine gute Idee), Exit-Codes über 255 zu verwenden (verwenden Sie 0-123 für den normalen Betrieb).

Alternative:

awk 'BEGIN{exit 56}'
perl -e 'exit 56'
python -c 'exit(56)'
expect -c 'exit 56'

(Diese kürzen den Exit-Code nicht auf 8 Bit).

Mit NetBSD findkönnen Sie:

find / -exit 56

1exit ist der Standardbefehl, um dies zu tun. Da es sich jedoch um ein spezielles Shell- Builtin handelt , ist es nicht erforderlich, dass das Dateisystem einen Befehl mit diesem Namen enthält, wie dies bei regulären Builtins der Fall ist, und die meisten Systeme enthalten keinen

Stéphane Chazelas
quelle
3
/* Public domain, http://creativecommons.org/publicdomain/zero/1.0/ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char **argv) {
    if(!strcasecmp(argv[0],"true")) return 0;
    else if (!strcasecmp(argv[0],"false")) return 1;
    else if(argc<2) {fputs("One argument required\n",stderr);return 1;}
    else if(!strcasecmp(argv[argc-1],"true")) return 0;
    else if(!strcasecmp(argv[argc-1],"false")) return 1;
    else return atoi(argv[argc-1]);
}

Speichern Sie dies in einer Datei mit dem Namen returncode.cundgcc -o returncode returncode.c

ThePiercingPrince
quelle
Zu den Aspekten: 1) Das Anwenden der CC0-Lizenz ohne Nennung als Affirmer ist wahrscheinlich keine gute Idee, und Sie sollten es so machen . 2) Programme, die so klein sind, sind für Ihr Urheberrecht zu trivial, um eine Rolle zu spielen könnte genauso gut die Lizenz weglassen.
Rhymoid
2
(1) Ich verstehe nicht, warum Sie argv[argc-1]stattdessen verwenden argv[1]und warum Sie sich nicht beschweren, wenn argc>2. (2) Ich wäre geneigt, den argv[1]Test vor dem argv[0]Test durchzuführen, wobei der Benutzer sagen kann, true 56oder false 56anstelle von returncode 56. Sie geben keine Nachricht, wenn argv[0]ein Wort ist und argc>0- das könnte verwirrend sein. (3) Ich bin besessen von Benutzerfreundlichkeit, also würde ich strcasecmpanstelle von verwenden strcmp. (4) Ich neige dazu, Parameter zu validieren und den Rückgabewert von nicht zu verwenden, atoiohne ihn zu verifizieren. Für ein 2 ¢ -Programm wie dieses ist es wohl egal.
G-Man sagt, dass Monica
Weder @ G-Man truenoch falseverarbeitet jedes Argument in Linux - Systemen
ThePiercingPrince
OK, das ist richtig - sie verarbeiten keine Argumente, einschließlich argv[0]; die Programme /bin/trueund /bin/falsesind verschiedene ausführbare Dateien, mit fest codierten Exit-Codes. Sie haben ein Programm geschrieben , das als installiert werden kann beide true und false(verbunden), die klug ist. In der Frage wird jedoch gefragt, wie ein benutzerdefinierter Beendigungsstatus abgerufen werden kann. Ihr Programm beantwortet diese Frage nur, wenn es unter einem anderen Dateinamen installiert ist. Solange Sie es argvtrotzdem betrachten, glaube ich, dass es das Niveau der Klugheit bewahren würde, wenn Sie es so tun, wie ich es vorschlage, indem Sie die Notwendigkeit eines dritten Links vermeiden.
G-Man sagt, dass Monica
0

Ich war mir nicht ganz sicher, ob Ihr einziges Problem mit dem exitBefehl darin bestand, die aktuelle Shell zu verlassen, aber in diesem Fall könnte eine Subshell funktionieren.

username@host$ $(exit 42)
username@host$ echo $?
42

Ich habe das gerade auf Cygwin Bash getestet und es funktioniert für mich.

Bearbeiten: Sorry, ich habe den Teil verpasst, der außerhalb eines Shell-Kontexts ausgeführt wurde. In diesem Fall würde dies nicht helfen, ohne es in ein .shSkript zu packen und dieses in Ihrer Umgebung auszuführen.

Mihir
quelle
4
$(exit 42)versucht die Ausgabe von exit 42als einfachen Befehl auszuführen , was wenig Sinn macht (es würde auch nicht funktionieren yash). (exit 42)( exitWird auch in einer Subshell ausgeführt, lässt aber die Ausgabe in Ruhe) wäre sinnvoller und portabler (sogar für csh oder die Bourne-Shell).
Stéphane Chazelas