Comando Unix che restituisce immediatamente un particolare codice di ritorno?


28

Esiste un comando Unix standard che fa qualcosa di simile al mio esempio di seguito

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

<cmd here>dovrebbe essere qualcosa che può essere eseguito fork e lascia 56 come codice di uscita quando il processo termina. I builtin exite returnshell non sono adatti a quello che sto cercando perché influenzano la shell invocante stessa uscendo da essa. <some cmd>dovrebbe essere qualcosa che posso eseguire in contesti non shell - ad esempio, invocando da uno script Python con subprocess.

Ad esempio, /usr/bin/falseesce sempre immediatamente con il codice di ritorno 1, ma mi piacerebbe controllare esattamente cos'è quel codice di ritorno. Ho potuto ottenere gli stessi risultati scrivendo il mio script wrapper

$ 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

ma spero che esista un comando Unix standard che possa farlo per me.


10
exitè l'unico a cui riesco a pensare, ma tende a finire il tuo guscio. bash -c 'exit 56'o bash -c "exit $1"potrebbe funzionare per te.
Tim Kennedy,

12
Che ne dici (exit 56)?
cuonglm,

6
Sembra davvero un XYProblem : qual è l'obiettivo finale di questo? Perché hai bisogno di un comando che restituisce come codice di uscita il numero che gli dai?
Olivier Dulac,

1
Beh, avete le truee falsebuilt-in, se avete bisogno di tornare 0 o 1.
gardenhead

1
correlati: il programma più piccolo (non portatile) per restituire un valore fisso in fase di compilazione: muppetlabs.com/~breadbox/software/tiny/teensy.html
Florian Castellane,

Risposte:


39
  1. Una returnfunzione basata funzionerebbe ed eviterebbe la necessità di aprire e chiudere un'altra shell (come da commento di Tim Kennedy ):

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

    Produzione:

    56
  2. usando exitin una subshell:

    (exit 56)

    Con shell diverse da quelle ksh93, ciò implica il fork di un processo aggiuntivo, quindi è meno efficiente di quanto sopra.

  3. bash/ zsh/ ksh93unico trucco:

    . <( echo return 56 )

    (ciò implica anche un ulteriore processo (e IPC con una pipe)).

  4. zshLe funzioni lambda:

    (){return 56}

Buon pensiero. Sfortunatamente, la mia domanda originale non era stata definita abbastanza bene: la necessità di "aprire e chiudere un'altra shell" era quasi un requisito di ciò che volevo fare. Ho modificato la mia domanda per richiedere che <some cmd>sia una cosa in grado di eseguire execve ().
Chris,

2
@Chris: per qualsiasi comando shell puoi renderlo execve () in grado di convertirlo in/bin/sh -c ...originalcommand...
psmears

3
Sono leggermente deluso dal fatto che? = 56 non funziona.
Giosuè,

@Joshua: forse lo fa? ma poi questa affezione ha avuto successo e hai $? impostato su 0 ...;)
Olivier Dulac l'

@OlivierDulac: No. Emette un errore di analisi.
Giosuè,

17

Non esiste un comando UNIX standard per restituire solo un valore specifico. Le utilità GNU Core forniscono truee falsesolo.

Tuttavia, puoi facilmente implementarlo da solo come ret:

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

Compilare:

cc ret.c -o ret

E corri:

./ret 56 ; echo $?

stampe:

56

Se hai bisogno che funzioni ovunque (dove bash è disponibile, cioè) senza installare strumenti aggiuntivi, probabilmente dovrai ricorrere al seguente comando come suggerito da @TimKennedy nei commenti:

bash -c 'exit 56'

Si noti che l' intervallo valido di valori di ritorno è compreso tra 0 e 255 inclusi .


1
truee falsesono anche in Unix (e anche POSIX), non solo in GNU.
Stéphane Chazelas,

@ StéphaneChazelas Grazie per averlo sottolineato. Come l'OP ha menzionato bash, in qualche modo ho assunto GNU - anche se la domanda stessa afferma "Unix".
TMH

14

Se è necessario che lo stato di uscita sia impostato da un comando eseguito. Non esiste un comando dedicato per quell'1 , ma puoi usare l'interprete di qualsiasi lingua che abbia la capacità di uscire con uno stato di uscita arbitrario. shè il più ovvio:

sh -c 'exit 56'

Con la maggior parte delle shimplementazioni, ciò è limitato ai codici di uscita da 0 a 255 ( shaccetterà valori maggiori ma potrebbe troncarlo o persino causare un segnale inviato al processo in esecuzione shcome con ksh93 per i codici da 257 a 320).

Un codice di uscita può essere qualsiasi intvalore intero ( ) ma si noti che è necessario recuperarlo con l' waitid()interfaccia in modo che il valore non venga troncato a 8 bit (su Linux, tuttavia è comunque troncato waitid()). Ecco perché è raro (e non una buona idea) utilizzare codici di uscita superiori a 255 (utilizzare 0-123 per il normale funzionamento).

In alternativa:

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

(quelli non troncano il codice di uscita a 8 bit).

Con NetBSD find, puoi fare:

find / -exit 56

1exit è il comando standard per farlo, ma essendo un builtin speciale della shell , non è necessario che ci sia anche un comando con quel nome nel file system come per i normali built-in, e la maggior parte dei sistemi non ne include uno


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]);
}

Salvalo in un file chiamato returncode.cegcc -o returncode returncode.c


In una nota semi-correlata: 1) applicare la licenza CC0 senza nominare te stesso come un affirmer non è probabilmente una buona idea, e dovresti farlo in questo modo , 2) programmi così piccoli sono troppo banali perché il tuo copyright sia importante, quindi potrebbe anche tralasciare la licenza.
Rhymoid,

2
(1) Non capisco perché stai usando argv[argc-1]invece argv[1]e perché non ti lamenti se argc>2. (2) Sarei propenso a fare il argv[1]test prima del argv[0]test, consentendo all'utente di dire true 56o false 56invece di returncode 56. Non dare un messaggio se argv[0]è una parola e argc>0- potrebbe essere fonte di confusione. (3) Sono ossessionato dalla facilità d'uso, quindi userei strcasecmpinvece di strcmp. (4) Tendo a convalidare i parametri e non utilizzo il valore restituito atoisenza verificarlo. Per un programma 2 ¢ come questo, suppongo che non abbia importanza.
G-Man dice "Ripristina Monica" il

@ G-Man Né truefalseelabora alcun argomento a sistemi Linux
ThePiercingPrince

OK, è corretto - non elaborano alcun argomento, incluso argv[0]; i programmi /bin/truee /bin/falsesono eseguibili diversi, con codici di uscita codificati. Hai scritto un programma che può essere installato come sia true e false(linked), che è intelligente. Ma la domanda chiede come ottenere uno stato di uscita specificato dall'utente. Il tuo programma risponde a questa domanda, ma solo se è installato con un nome file diverso. Fintanto che stai guardando argv, credo che farlo nel modo che suggerisco manterrebbe il livello di intelligenza, evitando la necessità di un terzo collegamento.
G-Man dice "Reinstate Monica" l'

0

Non ero esattamente sicuro che il tuo unico problema con il exitcomando fosse uscire dalla shell corrente, ma in tal caso, una subshell potrebbe funzionare.

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

Ho provato questo su Cygwin Bash proprio ora e funziona per me.

Modifica: mi dispiace, ho perso la parte di eseguirlo al di fuori di un contesto shell. In tal caso, ciò non sarebbe d'aiuto senza includerlo in uno .shscript ed eseguirlo dal proprio ambiente.


4
$(exit 42)cerca di eseguire l'output di exit 42come un semplice comando che ha poco senso (inoltre non funzionerebbe con yash). (exit 42)(eseguito anche exitin una subshell, ma lascia solo il suo output) avrebbe più senso e sarebbe più portabile (anche su csh o shell Bourne).
Stéphane Chazelas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.