Comando Unix que retorna imediatamente um código de retorno específico?

28

Existe um comando Unix padrão que faz algo semelhante ao meu exemplo abaixo

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

<cmd here>deve ser algo que possa ser executado em fork e deixa 56 como o código de saída quando o processo é encerrado. Os componentes internos exite returnshell não são adequados para o que estou procurando, pois afetam o próprio invocador ao sair dele. <some cmd>deve ser algo que eu possa executar em contextos não shell - por exemplo, invocar a partir de um script Python com subprocess.

Por exemplo, /usr/bin/falsesempre sai imediatamente com o código de retorno 1, mas eu gostaria de controlar exatamente o que é esse código de retorno. Eu poderia alcançar os mesmos resultados escrevendo meu próprio script de 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

mas espero que exista um comando Unix padrão que possa fazer isso por mim.

Chris
fonte
10
exité o único que consigo pensar, mas tende a acabar com o seu shell. bash -c 'exit 56'ou bash -c "exit $1"pode funcionar para você.
Tim Kennedy
12
Que tal (exit 56)?
cuonglm
6
Isso realmente soa como um problema XY : qual é o objetivo final disso? Por que você precisa de um comando que retorne como código de saída o número fornecido?
quer
1
Bem, você tem os truee falsebuilt-ins, se você precisa de retornar 0 ou 1.
gardenhead
1
Relacionados: (não portátil) menor programa para retornar um valor de compilação em tempo fixo: muppetlabs.com/~breadbox/software/tiny/teensy.html
Florian Castellane

Respostas:

39
  1. A returnfunção de base iria funcionar, e evita a necessidade de abrir e fechar outro shell, (como por Tim Kennedy comentário 's ):

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

    Saída:

    56
  2. usando exitem um subshell:

    (exit 56)

    Com cascas que não sejam ksh93, isso implica bifurcar um processo extra, portanto, é menos eficiente do que o descrito acima.

  3. bash/ zsh/ ksh93único truque:

    . <( echo return 56 )

    (isso também implica um processo extra (e IPC com um pipe)).

  4. zshFunções lambda de:

    (){return 56}
agc
fonte
Bom pensamento. Infelizmente, minha pergunta original não foi bem definida - a necessidade de "abrir e fechar outro shell" era quase um requisito do que eu queria fazer. Eu editei minha pergunta para exigir que isso <some cmd>seja uma coisa executável ().
10286 Chris
2
@ Chris: Para qualquer comando da shell que pode torná-lo execve () poder, convertendo-a/bin/sh -c ...originalcommand...
psmears
3
Estou levemente decepcionado que? = 56 não funcione.
Joshua
@ Josué: talvez faz? mas essa afetação foi bem-sucedida e você tem $? definido como 0 ...;)
Olivier Dulac 11/10
@OlivierDulac: Não. Ele cospe um erro de análise.
Joshua
17

Não há comando UNIX padrão apenas para retornar um valor específico. Os utilitários principais do GNU fornecem truee falsesomente.

No entanto, você pode facilmente implementar isso como ret:

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

Compilar:

cc ret.c -o ret

E corra:

./ret 56 ; echo $?

Impressões:

56

Se você precisar que isso funcione em qualquer lugar (onde o bash está disponível, ou seja) sem instalar nenhuma ferramenta extra, você provavelmente precisará recorrer ao seguinte comando, como @TimKennedy sugerido nos comentários:

bash -c 'exit 56'

Observe que o intervalo válido de valores de retorno é 0..255 inclusive .

tmh
fonte
1
truee falseestão no Unix (e até no POSIX) também, não apenas no GNU.
Stéphane Chazelas 10/10
@ StéphaneChazelas Obrigado por apontar isso. Como o OP mencionou o bash, de alguma forma assumi o GNU - embora a própria pergunta afirme 'Unix'.
TMH
14

Se você precisar que o status de saída seja definido por um comando executado. Não existe um comando dedicado para esse 1 , mas você pode usar o intérprete de qualquer idioma que possua a capacidade de sair com um status de saída arbitrário. shé o mais óbvio:

sh -c 'exit 56'

Na maioria das shimplementações, isso é limitado aos códigos de saída de 0 a 255 ( shaceitará valores maiores, mas poderá truncá-lo ou até causar um sinal para o processo ser executado shcomo ksh93 nos códigos de 257 a 320).

Um código de saída pode ser qualquer intvalor inteiro ( ), mas observe que você precisa recuperá-lo com a waitid()interface para que o valor não seja truncado para 8 bits (no Linux, ele ainda é truncado waitid()também). Por isso, é raro (e não é uma boa ideia) usar códigos de saída acima de 255 (use 0-123 para operação normal).

Alternativamente:

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

(aqueles não truncam o código de saída para 8 bits).

Com o NetBSD find, você pode:

find / -exit 56

1exit é o comando padrão para fazer isso, mas, sendo um embutido especial do shell , não é necessário que também exista um comando com esse nome no sistema de arquivos, como para embutidos regulares, e a maioria dos sistemas não inclui um

Stéphane Chazelas
fonte
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]);
}

Salve isso em um arquivo chamado returncode.cegcc -o returncode returncode.c

ThePiercingPrince
fonte
Em uma nota semi-relacionada: 1) aplicar a licença CC0 sem se nomear um afirmador provavelmente não é uma boa idéia, e você deve fazer assim , 2) programas pequenos assim são triviais demais para que seus direitos autorais sejam importantes; pode deixar de fora a licença.
Rhymoid
2
(1) Eu não entendo por que você está usando argv[argc-1], em vez de argv[1], e por que você não está reclamando se argc>2. (2) Eu estaria inclinado a fazer o argv[1]teste antes do argv[0]teste, permitindo que o usuário dissesse true 56ou false 56não returncode 56. Você não dá uma mensagem se argv[0]for uma palavra e argc>0- isso pode ser confuso. (3) Eu sou obcecado pela facilidade de uso, então eu usaria em strcasecmpvez de strcmp. (4) Eu costumo validar parâmetros e não usar o valor de retorno atoisem verificar. Para um programa 2 ¢ como esse, acho que não importa.
G-Man Diz 'Reinstate Monica'
@ G-Man Nem truenem falseprocessa qualquer argumento em sistemas Linux
ThePiercingPrince
OK, está correto - eles não processam nenhum argumento, inclusive argv[0]; os programas /bin/truee /bin/falsesão executáveis ​​diferentes, com códigos de saída codificados. Você escreveu um programa que pode ser instalado como ambos true e false(ligada), que é inteligente. Mas a pergunta pergunta como obter um status de saída especificado pelo usuário. Seu programa responde a essa pergunta, mas somente se ele estiver instalado com um nome de arquivo diferente. Enquanto você estiver olhando de argvqualquer maneira, acredito que fazer da maneira que sugiro manteria o nível de inteligência, evitando a necessidade de um terceiro link.
G-Man diz que 'Reinstate Monica'
0

Eu não tinha exatamente certeza se o seu único problema com o exitcomando era sair do shell atual, mas se sim, um subshell pode funcionar.

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

Eu testei isso no Cygwin Bash agora e funciona para mim.

Edit: Desculpe, eu perdi a parte de executá-lo fora de um contexto de shell. Nesse caso, isso não ajudaria sem envolvê-lo em um .shscript e executá-lo em seu ambiente.

Mihir
fonte
4
$(exit 42)tenta executar a saída exit 42como um comando simples que faz pouco sentido (também não funcionaria yash). (exit 42)(também é executado exitem um subshell, mas deixa sua saída em branco) faria mais sentido e seria mais portátil (mesmo para o csh ou o shell Bourne).
Stéphane Chazelas 10/10