Implicit avkastning i bash-funktioner?

Säg att jag har en bash-funktion så:

gmx(){ echo "foo"; } 

kommer den här funktionen att vara implicit returnera utgångsvärdet för kommandot echo, eller är det nödvändigt med retur?

gmx(){ echo "foo"; return $? } 

Jag antar att vägen bash fungerar, utgångsstatusen för det slutliga kommandot för bash-funktionen är den som blir ”returnerad”, men inte 100% säker.

Svar

return returnerar ett uttryckligt från en skalfunktion eller” punktskript ”(ett skript). Om return inte körs görs en implicit avkastning i slutet av skalfunktionen eller punktskriptet.

Om return körs utan en parameter, det motsvarar att returnera utgångsstatus för det senast körda kommandot.

Så fungerar return i alla POSIX skal.

Till exempel,

gmx () { echo "foo" return "$?" } 

motsvarar därför

gmx () { echo "foo" return } 

vilket är samma som

gmx () { echo "foo" } 

I allmänhet är det mycket sällan du behöver använda $? alls. Det behövs egentligen bara om du behöver spara det för framtida bruk, till exempel om du behöver undersöka dess värde flera gånger (i vilket fall skulle du tilldela värdet till en variabel och utföra en serie tester på den variabeln). / p>

Kommentarer

  • En nackdel med att använda return är att för funktioner som definieras som f() (...; cmd; return), förhindrar det den optimering som några skal gör för att köra cmd i samma process som subshell. Med många skal betyder det också att funktionens utgångsstatus inte ’ t bär informationen att cmd har dödats när den har (de flesta skal kan ’ t hämta informationen ändå).
  • Observera att med pdksh och några av dess derivat (som OpenBSD sh eller posh), du ’ d behöver return -- "$?" om det fanns en chans att det sista kommandot var en funktion som returnerade ett negativt tal. mksh (även baserat på pdksh) förbjuder funktioner att returnera negativa värden.
  • tack för det här hjälper jag antar att jag inte ’ t förstår hur return x fungerar annorlunda än exit x … det enda jag vet är att return x avslutar inte den aktuella processen.
  • @AlexanderMills Tja, det ’ är vad jag sa: return används för att återvända från en funktion eller ett punktskript. exit gör något helt annat (avslutar en process).
  • ja det är vettigt Jag tror att jag börjar få bättre grepp om detta

Svar

Från bash(1) mansidan:

När den körs är utgångsstatus för en funktion utgångsstatus för det senaste kommandot som körs i kroppen.

Kommentarer

  • rätt, och en följd kan vara att returuttalandet inte är mer än utgångsstatus?
  • Jag antar att return är ett inbyggt kommando – även om return 1 skiljer sig från exit 1, etc så
  • ” returnera [n]: Gör att en funktion stoppar körningen och returnerar det värde som anges av n till dess anropare. Om n utelämnas är returstatusen för det sista kommandot som utfördes i funktionskroppen. ” (ibid) Så, return tvingar utgångsstatus för en funktion till ett specifikt värde om det anges.
  • @AlexandwrMills Ja, return och exit är båda inbyggda, förutom att return endast kan användas inom funktionen. Du kan ’ t avsluta ett skript med return. Utgångsstatus är ett värde som kommandot returnerar. return är ett kommando som returnerar det värdet. Så ” returuttalande är inget annat än utgångsstatus ” är inte riktigt korrekt. Det ena är ett värde, det andra är kommandot plus värde.
  • @AlexanderMills, return återvänder från funktionen, exit går ut ur hela skalet. Det ’ är exakt samma som i, säg C med return vs. exit(n), eller return vs. sys.exit() i Python.

Svar

Jag lägger bara till några försiktighetsanmärkningar till de redan givna svaren:

  • Även om return har en mycket speciell betydelse för skalet, ur en syntax synvinkel, är det ett inbyggt kommandot och ett returuttalande tolkas som alla andra enkla kommandon. Så det betyder att som i argumentet för alla andra kommandon, $? när det inte citeras, skulle vara föremål för split + glob

    Så du måste citera det $? för att undvika det:

    return "$?" 
  • return accepterar vanligtvis inget alternativ (ksh93 ”s accepterar det vanliga --help, --man, --author … dock). Det enda argumentet det förväntar sig (valfritt) är returkoden. Området för accepterade returkoder varierar från skal till skal, och om något värde utanför 0..255 återspeglas korrekt i

varierar också från skal till skal. Se Standardutgångskod när processen avslutas? för detaljer om det.

De flesta skal accepterar negativa tal (trots allt skickas argumentet till _exit() / exitgroup() systemanrop är ett int, så med värden som omfattar minst – 2 31 till 2 31 -1, så det är bara vettigt att skal accepterar samma intervall för dess funktioner).

De flesta skal använder waitpid() och co. API för att hämta utgångsstatus men i vilket fall det trunkeras till ett tal mellan 0 och 255 när lagras i $?. Även om en funktion anropas involverar inte att leka en process och använde waitpid() för att hämta sin utgångsstatus eftersom allt görs i samma process, många skal efterliknar också att waitpid() beteende när man anropar funktioner. Vilket innebär att även om du ringer till return med ett negativt värde, kommer $? att innehålla ett positivt tal.

Nu, bland de skal vars return accepterar negativa tal (ksh88, ksh93, bash, zsh, pdksh och andra derivat än mksh, yash), finns det några ( pdksh och yash) som behöver skrivas som return -- -123 eftersom annars -123 tas som tre -1, -2, -3 ogiltiga alternativ.

Som pdksh och dess de rivativ (som OpenBSD sh eller posh) spara det negativa talet i $? att göra return "$?" skulle misslyckas när $? innehåller ett negativt tal (vilket skulle hända när kommandot för sista körningen var en funktion som returnerade ett negativt tal ).

return -- "$?" skulle vara bättre i dessa skal. Observera att även om syntax stöds av de flesta skalen inte POSIX och i praktiken inte stöds av mksh och askderivat.

Så, för att sammanfatta, med pdksh-baserade skal kan du använda negativa siffror i argument till funktioner, men om du gör det return "$@" fungerar inte. I andra skal fungerar return "$@" fungerar och du bör undvika att använda negativa siffror (eller siffror utanför 0..255) som argument för return.

  • I alla skal som jag känner kommer att ringa return inifrån en subshell som körs inuti en funktion att subshell avslutas (med angiven exitstatus om någon eller den för det sista kommandot kör), men kommer annars inte att ge en återgång från funktionen (för mig är det oklart om POSIX ger dig den garantin, vissa hävdar att exit bör användas istället för att avsluta subshells inuti funktioner). Till exempel

    f() { (return 3) echo "still inside f. Exit status: $?" } f echo "f exit status: $?" 

    kommer att mata ut:

    still inside f. Exit status: 3 f exit status: 0 
  • Svar

    Ja, det implicita returvärdet för en funktion är utgångsstatus för den senaste exekverade -kommando. Det gäller också när som helst i ett skalskript. När som helst i skriptets exekveringssekvens är nuvarande utgångsstatus utgångsstatus för det senast utförda kommandot. Även kommando som körs som en del av en variabel tilldelning: var=$(exit 34). Skillnaden med funktioner är att en funktion kan ändra utgångsstatus i slutet av utförandet av funktionen.

    Det alternativa sättet att ändra ”nuvarande utgångsstatus” är att starta ett underskal och avsluta det med eventuell utgångsstatus som behövs:

    $ $(exit 34) $ echo "$?" 34 

    Och ja, utgångsstatus expansion behöver citeras:

    $ IFS="123" $ $(exit 34) $ echo $? 4 

    A (exit 34) fungerar också.
    Vissa kan hävda att en mer robust konstruktion bör vara $(return 34), och att en exit bör ”avsluta” det manus som körs. Men $(return 34) fungerar inte med någon version av bash. Så det är inte bärbart.

    Det säkraste sättet att ställa in en utgångsstatus är att använda den som den var utformad för att fungera, definiera och return från en funktion :

    exitstatus(){ return "${1:-"$?"}"; } 

    Så i slutet av en funktion. det motsvarar exakt att ha antingen ingenting eller return eller return "$?". Slutet på en funktion behöver inte betyda den ”sista kodraden för en funktion”.

    #!/bin/sh exitstatus(){ a="${1:-"$?"}"; return "$a"; } gmx(){ if [ "$1" = "one" ]; then printf "foo "; exitstatus 78 return "$?" elif [ "$1" = "two" ]; then printf "baz "; exitstatus 89 return else printf "baz "; exitstatus 90 fi } 

    Skrivs ut:

    $ ./script foo 78 baz 89 baz 90 

    Den enda praktiska användningen för "$?" är att antingen skriva ut dess värde: echo "$?" det i en variabel (eftersom det är ett kortvarigt värde och ändras med varje kommando som körs): exitstatus=$? (kom ihåg att citera variabeln i kommandon som export EXITSTATUS="$?".

    I kommandot return är det giltiga värdena i allmänhet 0 till 255, men förstå att värdena för 126 + n används av vissa skal för att signalera speciell utgångsstatus, så den allmänna rekommendationen är att använda 0-125.

    Lämna ett svar

    Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *