Polecenie uniksowe, które natychmiast zwraca określony kod powrotu?

28

Czy istnieje standardowe polecenie Unix, które robi coś podobnego do mojego przykładu poniżej?

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

<cmd here>powinno być czymś, co można wykonać za pomocą wideł, i pozostawia 56 jako kod wyjścia, gdy proces się kończy. Te exiti returnpowłoki builtins nie nadają się do tego, co szukam, ponieważ wpływają one na skorupę powołując się poprzez wychodzenia z niego. <some cmd>powinno być czymś, co mogę wykonać w kontekście innym niż shell - np. wywołując ze skryptu Python za pomocą subprocess.

Np. /usr/bin/falseZawsze wychodzi natychmiast z kodem powrotu 1, ale chciałbym dokładnie kontrolować, co to jest kod powrotu. Mogę osiągnąć te same wyniki, pisząc własny skrypt opakowania

$ 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

ale mam nadzieję, że istnieje standardowa komenda Uniksa, która może to dla mnie zrobić.

Chris
źródło
10
exitjest jedynym, o którym mogę myśleć, ale ma tendencję do kończenia twojej powłoki. bash -c 'exit 56'lub bash -c "exit $1"może pracować dla ciebie.
Tim Kennedy,
12
Jak o (exit 56)?
cuonglm,
6
To naprawdę brzmi jak XYProblem : jaki jest tego ostateczny cel? Dlaczego potrzebujesz polecenia, które zwraca jako kod wyjścia podany numer?
Olivier Dulac,
1
Cóż, masz wbudowane truei falsewbudowane, jeśli chcesz zwrócić 0 lub 1.
Gardenhead
1
powiązane: (nieprzenośny) najmniejszy program do zwracania stałej wartości czasu kompilacji: muppetlabs.com/~breadbox/software/tiny/teensy.html
Florian Castellane

Odpowiedzi:

39
  1. returnFunkcja oparta będzie działać, i unika konieczności otwierać i zamykać kolejną powłokę, (zgodnie Tim Kennedy komentarzu „s ):

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

    Wydajność:

    56
  2. za exitpomocą podpowłoki:

    (exit 56)

    W przypadku powłok innych niż ksh93oznacza to rozwidlenie dodatkowego procesu, więc jest mniej wydajny niż powyższe.

  3. bash/ zsh/ ksh93tylko trik:

    . <( echo return 56 )

    (co oznacza również dodatkowy proces (i IPC z rurą)).

  4. zshfunkcje lambda:

    (){return 56}
agc
źródło
Dobra myśl. Niestety moje pierwotne pytanie nie zostało wystarczająco dobrze zdefiniowane - konieczność „otwarcia i zamknięcia kolejnej powłoki” była niemal wymogiem tego, co chciałem zrobić. Zredagowałem swoje pytanie, aby wymagać, aby było <some cmd>to możliwe w execve ().
Chris,
2
@Chris: Dla każdego polecenia powłoki możesz go uruchomić (), konwertując go na/bin/sh -c ...originalcommand...
psmears,
3
Jestem lekko rozczarowany, że? = 56 nie działa.
Joshua
@Joshua: może tak jest? ale potem ta afekcja się powiodła, a ty masz $? ustawiony na 0 ...;)
Olivier Dulac
@OlivierDulac: Nie. Wyrzuca błąd analizy.
Joshua
17

Nie ma standardowej komendy UNIX służącej do zwrócenia określonej wartości. GNU Core Utilies zapewnia truei falsetylko.

Możesz to jednak łatwo zaimplementować samodzielnie ret:

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

Skompilować:

cc ret.c -o ret

I biegnij:

./ret 56 ; echo $?

Wydruki:

56

Jeśli potrzebujesz, aby działało to wszędzie (tam, gdzie dostępna jest wersja bash) bez instalowania dodatkowych narzędzi, prawdopodobnie musisz użyć następującego polecenia, jak sugeruje @TimKennedy w komentarzach:

bash -c 'exit 56'

Należy pamiętać, że prawidłowy zakres zwracanych wartości wynosi 0..255 włącznie .

thh
źródło
1
truei falsesą również w systemie Unix (a nawet POSIX), nie tylko w GNU.
Stéphane Chazelas,
@ StéphaneChazelas Dzięki za zwrócenie na to uwagi. Jak OP wspomniało o bashu, jakoś założyłem GNU - mimo że samo pytanie brzmi „Unix”.
tmh
14

Jeśli potrzebujesz, aby status wyjścia był ustawiany przez wykonywane polecenia. Nie ma dedykowanego polecenia dla tego 1 , ale można użyć interpretera dowolnego języka, który ma możliwość wyjścia z dowolnym statusem wyjścia. shjest najbardziej oczywisty:

sh -c 'exit 56'

W przypadku większości shimplementacji ogranicza się to do kodów wyjściowych od 0 do 255 ( shzaakceptuje większe wartości, ale może je skrócić, a nawet spowodować wysłanie sygnału do procesu wykonującego się shjak w przypadku ksh93 dla kodów 257 do 320).

Kod wyjścia może być dowolną liczbą całkowitą ( int), ale pamiętaj, że musisz pobrać go za pomocą waitid()interfejsu, aby wartość nie została obcięta do 8 bitów (w Linuksie również nadal jest obcięta waitid()). Dlatego rzadko (i nie jest to dobry pomysł) używanie kodów wyjścia powyżej 255 (użyj 0-123 do normalnej pracy).

Alternatywnie:

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

(nie obcinają kodu wyjścia do 8 bitów).

Dzięki NetBSD findmożesz:

find / -exit 56

1exit jest standardowym poleceniem służącym do tego, ale ponieważ jest to wbudowane specjalne narzędzie powłoki , nie ma wymogu, aby w systemie plików istniało również polecenie o tej nazwie, tak jak w przypadku zwykłych wbudowanych systemów, a większość systemów nie ma takiego

Stéphane Chazelas
źródło
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]);
}

Zapisz to w pliku o nazwie returncode.cigcc -o returncode returncode.c

ThePiercingPrince
źródło
W przypadku częściowo powiązanej uwagi: 1) zastosowanie licencji CC0 bez podawania się jako afirmator prawdopodobnie nie jest dobrym pomysłem i powinieneś to zrobić w ten sposób , 2) tak małe programy są zbyt trywialne, aby twoje prawa autorskie miały znaczenie, więc równie dobrze może pominąć licencję.
Rhymoid,
2
(1) Nie rozumiem dlaczego używasz argv[argc-1]zamiast argv[1], i dlaczego nie jesteś sędzią, jeśli argc>2. (2) Byłbym skłonny zrobić argv[1]test przed argv[0]testem, pozwalając użytkownikowi powiedzieć true 56lub false 56zamiast returncode 56. Nie podajesz wiadomości, jeśli argv[0]jest to słowo i argc>0- to może być mylące. (3) Mam obsesję na punkcie łatwości obsługi, więc skorzystałbym strcasecmpzamiast strcmp. (4) Mam tendencję do sprawdzania poprawności parametrów i nie używam wartości zwracanej atoibez jej weryfikacji. Wydaje mi się, że dla takiego programu 2 ¢ nie ma to znaczenia.
G-Man mówi „Przywróć Monikę”
@ G-Man Ani truenie falseprzetwarza żadnych argumentów w systemach Linux
ThePiercingPrince
OK, zgadza się - nie przetwarzają żadnych argumentów, w tym argv[0]; programy /bin/truei /bin/falsesą różnymi plikami wykonywalnymi z zakodowanymi kodami wyjścia. Napisałeś program, który można zainstalować zarówno jako ( truei falsepołączony), co jest sprytne. Ale pytanie dotyczy sposobu uzyskania statusu wyjścia określonego przez użytkownika. Twój program odpowiada na to pytanie, ale tylko jeśli jest zainstalowany pod inną nazwą. Tak długo, jak na to patrzysz argv, uważam, że robienie tego w sposób, który sugeruję, utrzyma poziom sprytu, unikając potrzeby trzeciego łącza.
G-Man mówi „Przywróć Monikę”
0

Nie byłem do końca pewien, czy twoim jedynym problemem z exitpoleceniem było wyjście z bieżącej powłoki, ale jeśli tak, podpowłoka może działać.

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

Właśnie przetestowałem to na Cygwin Bash i to działa dla mnie.

Edycja: Przepraszam, że tęskniłem za działaniem poza kontekstem powłoki. W takim przypadku thsi nie pomogłoby bez zawinięcia go w .shskrypt i wykonania go ze środowiska.

Mihir
źródło
4
$(exit 42)próbuje wykonać dane wyjściowe exit 42jako proste polecenie, które nie ma sensu (nie działałoby również yash). (exit 42)(działający również exitw podpowłoce, ale pozostawiający dane wyjściowe w spokoju) miałby więcej sensu i byłby bardziej przenośny (nawet do csh lub powłoki Bourne'a).
Stéphane Chazelas,