¿Comando Unix que devuelve inmediatamente un código de retorno particular?


28

¿Existe un comando estándar de Unix que haga algo similar a mi ejemplo a continuación?

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

<cmd here>debe ser algo que se pueda ejecutar con fork y deje 56 como código de salida cuando el proceso finalice. Los builtins exity returnshell no son adecuados para lo que estoy buscando porque afectan al shell invocador al salir de él. <some cmd>debería ser algo que pueda ejecutar en contextos que no sean de shell, por ejemplo, invocar desde un script Python con subprocess.

Por ejemplo, /usr/bin/falsesiempre sale inmediatamente con el código de retorno 1, pero me gustaría controlar exactamente qué es ese código de retorno. Podría lograr los mismos resultados escribiendo mi propio script de envoltura

$ 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

pero espero que exista un comando estándar de Unix que pueda hacer esto por mí.


10
exites el único que se me ocurre, pero tiende a terminar con su caparazón. bash -c 'exit 56'o bash -c "exit $1"podría funcionar para ti.
Tim Kennedy

12
¿Qué tal (exit 56)?
Cuonglm

66
Esto realmente suena como un problema XY : ¿cuál es el objetivo final de esto? ¿Por qué necesita un comando que devuelve como código de salida el número que le da?
Olivier Dulac

1
Bueno, tienes los truee falseincorporados si necesitas devolver 0 o 1.
gardenhead

1
relacionado: (no portátil) programa más pequeño para devolver un valor fijo en tiempo de compilación: muppetlabs.com/~breadbox/software/tiny/teensy.html
Florian Castellane

Respuestas:


39
  1. Una returnfunción basada funcionaría y evita la necesidad de abrir y cerrar otro shell (según el comentario de Tim Kennedy ):

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

    Salida:

    56
  2. utilizando exiten una subshell:

    (exit 56)

    Con otros caparazones distintos ksh93, eso implica bifurcar un proceso adicional, por lo que es menos eficiente que el anterior.

  3. bash/ zsh/ ksh93solo truco:

    . <( echo return 56 )

    (eso también implica un proceso adicional (e IPC con una tubería)).

  4. zshLas funciones lambda de:

    (){return 56}

Buen pensamiento. Desafortunadamente, mi pregunta original no estaba bien definida: la necesidad de "abrir y cerrar otro shell" era casi un requisito de lo que quería hacer. Edité mi pregunta para exigir que <some cmd>sea ​​una cosa ejecutable ().
Chris

2
@Chris: Para cualquier comando de shell, puede hacerlo execve () convirtiéndolo a/bin/sh -c ...originalcommand...
psmears

3
Estoy un poco decepcionado de que? = 56 no funciona.
Joshua

@ Joshua: tal vez lo hace? pero entonces esta afectación fue exitosa y ¿tienes $? establecido en 0 ...;)
Olivier Dulac

@ OlivierDulac: No lo hace. Escupe un error de análisis.
Joshua

17

No existe un comando UNIX estándar para devolver un valor específico. Las utilidades principales de GNU proporcionan truey falsesolo.

Sin embargo, puede implementarlo fácilmente usted mismo como ret:

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

Compilar:

cc ret.c -o ret

Y correr:

./ret 56 ; echo $?

Huellas dactilares:

56

Si necesita que esto funcione en todas partes (donde está disponible bash, es decir) sin instalar ninguna herramienta adicional, probablemente deba recurrir al siguiente comando como sugirió @TimKennedy en los comentarios:

bash -c 'exit 56'

Tenga en cuenta que el rango válido de valores de retorno es 0..255 inclusive .


1
truey falseestán en Unix (e incluso POSIX) también, no solo en GNU.
Stéphane Chazelas

@ StéphaneChazelas Gracias por señalar eso. Como el OP mencionó bash, de alguna manera asumí GNU, a pesar de que la pregunta en sí misma dice 'Unix'.
tmh

14

Si necesita que los comandos ejecutados establezcan el estado de salida. No hay un comando dedicado para ese 1 , pero puede usar el intérprete de cualquier idioma que tenga la capacidad de salir con un estado de salida arbitrario. shes el más obvio:

sh -c 'exit 56'

Con la mayoría de las shimplementaciones, eso se limita a los códigos de salida 0 a 255 ( shaceptará valores mayores pero puede truncarlo o incluso hacer que se envíe una señal al proceso que se ejecuta shcomo con ksh93 para los códigos 257 a 320).

Un código de salida puede ser cualquier intvalor entero ( ), pero tenga en cuenta que necesita recuperarlo con la waitid()interfaz para que el valor no se trunca a 8 bits (en Linux, sin embargo, también se trunca waitid()). Por eso es raro (y no es una buena idea) usar códigos de salida superiores a 255 (use 0-123 para el funcionamiento normal).

Alternativamente:

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

(esos no truncan el código de salida a 8 bits).

Con NetBSD find, puedes hacer:

find / -exit 56

1exit es el comando estándar para hacer eso, pero al ser un intérprete de comandos especial de shell , no hay ningún requisito de que también haya un comando con ese nombre en el sistema de archivos, como para las incorporaciones regulares, y la mayoría de los sistemas no incluirán 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]);
}

Guarde esto en un archivo llamado returncode.cygcc -o returncode returncode.c


En una nota semi-relacionada: 1) aplicar la licencia CC0 sin nombrarse como afirmador probablemente no sea una buena idea, y debe hacerlo así , 2) los programas tan pequeños son demasiado triviales para que sus derechos de autor importen, por lo que bien podría dejar de lado la licencia.
Rhymoid

2
(1) No entiendo por qué estás usando en argv[argc-1]lugar de argv[1], y por qué no te quejas si argc>2. (2) Me inclinaría a hacer la argv[1]prueba antes de la argv[0]prueba, permitiendo al usuario decir true 56o en false 56lugar de returncode 56. No da un mensaje si argv[0]es una palabra y argc>0eso podría ser confuso. (3) Estoy obsesionado con la facilidad de uso, por lo que usaría en strcasecmplugar de strcmp. (4) Tiendo a validar los parámetros y no usar el valor de retorno de atoisin verificarlo. Para un programa de 2 ¢ como este, supongo que no importa.
G-Man dice 'reinstalar a Monica' el

@ G-Man Ni trueni falseprocesa ningún argumento en sistemas Linux
ThePiercingPrince

OK, eso es correcto: no procesan ningún argumento, incluido argv[0]; los programas /bin/truey /bin/falseson ejecutables diferentes, con códigos de salida codificados. Has escrito un programa que se puede instalar como ambos true y false(vinculado), lo cual es inteligente. Pero la pregunta pregunta cómo obtener un estado de salida especificado por el usuario. Su programa responde a esa pregunta, pero solo si está instalado con un nombre de archivo diferente. Mientras lo veas de argvtodos modos, creo que hacerlo de la manera que sugiero mantendría el nivel de inteligencia, evitando la necesidad de un tercer enlace.
G-Man dice 'Restablecer a Monica' el

0

No estaba exactamente seguro de si su único problema con el exitcomando era salir del shell actual, pero si es así, un subshell podría funcionar.

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

Probé esto en Cygwin Bash justo ahora y funciona para mí.

Editar: Lo siento, me perdí la parte de ejecutarlo fuera de un contexto de shell. En ese caso, esto no ayudaría sin envolverlo dentro de un .shscript y ejecutarlo desde su entorno.


44
$(exit 42)intenta ejecutar la salida de exit 42como un comando simple que tiene poco sentido (tampoco funcionaría con yash). (exit 42)(también se ejecuta exiten un subshell, pero deja solo su salida) tendría más sentido y sería más portátil (incluso para csh o el shell Bourne).
Stéphane Chazelas
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.