Discussion:
Waarom wordt de foutcode niet bewaard
(te oud om op te antwoorden)
Cecil Westerhof
2023-11-05 21:26:00 UTC
Permalink
Als ik doe:
echo $((1 / 0)) || :
echo ${?}

Dan krijg ik:
1

Als ik echter doe:
sa-update || :
echo ${?}

Dan krijg ik:
0

Terwijl:
sa-update
echo ${?}

oplevert:
1

Waarom wordt in het eerste geval de foutcode wel bewaard en in het
tweede geval niet?
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
Cecil Westerhof
2023-11-05 21:56:24 UTC
Permalink
Post by Cecil Westerhof
echo ${?}
1
echo ${?}
0
sa-update
echo ${?}
1
Waarom wordt in het eerste geval de foutcode wel bewaard en in het
tweede geval niet?
Ik heb een oplossing gevonden, maar ik ben nog steeds benieuwd naar
het verschil bij de bovenstaande commando's.

Oplossing:
sa-update && retVal=${?} || retVal=${?}
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
Richard Lucassen
2023-11-06 07:06:26 UTC
Permalink
On Sun, 05 Nov 2023 22:56:24 +0100
Post by Cecil Westerhof
Ik heb een oplossing gevonden, maar ik ben nog steeds benieuwd naar
het verschil bij de bovenstaande commando's.
sa-update && retVal=${?} || retVal=${?}
sa-update
EXITCODE=$?
<verdere code>
echo "de exitcode van sa-update is ${EXITCODE}"

M.a.w.: stop de exitcode direct in een var. Dan raak je die niet meer
kwijt. Dan vang je ook meteen alle andere exitcodes (dus niet 0 of 1)
af, zoals bij wget of rsync.
--
Richard Lucassen <***@lucassen.org>
Cecil Westerhof
2023-11-06 10:08:18 UTC
Permalink
Post by Richard Lucassen
On Sun, 05 Nov 2023 22:56:24 +0100
Post by Cecil Westerhof
Ik heb een oplossing gevonden, maar ik ben nog steeds benieuwd naar
het verschil bij de bovenstaande commando's.
sa-update && retVal=${?} || retVal=${?}
sa-update
EXITCODE=$?
<verdere code>
echo "de exitcode van sa-update is ${EXITCODE}"
M.a.w.: stop de exitcode direct in een var. Dan raak je die niet meer
kwijt. Dan vang je ook meteen alle andere exitcodes (dus niet 0 of 1)
af, zoals bij wget of rsync.
Oeps, belangrijk onderdeel vergeten te noemen. 🥵
Ik gebruik in (bijna al) mijn scripts:
set -o errexit

Dat was waarom ik aan het truken was.
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
De ongekruisigde
2023-11-06 10:43:13 UTC
Permalink
Post by Cecil Westerhof
Post by Richard Lucassen
On Sun, 05 Nov 2023 22:56:24 +0100
Post by Cecil Westerhof
Ik heb een oplossing gevonden, maar ik ben nog steeds benieuwd naar
het verschil bij de bovenstaande commando's.
sa-update && retVal=${?} || retVal=${?}
sa-update
EXITCODE=$?
<verdere code>
echo "de exitcode van sa-update is ${EXITCODE}"
M.a.w.: stop de exitcode direct in een var. Dan raak je die niet meer
kwijt. Dan vang je ook meteen alle andere exitcodes (dus niet 0 of 1)
af, zoals bij wget of rsync.
Oeps, belangrijk onderdeel vergeten te noemen. 🥵
set -o errexit
lees dan dit nog maar eens goed door:

https://stackoverflow.com/questions/44080974/if-errexit-is-on-how-do-i-run-a-command-that-might-fail-and-get-its-exit-code
Post by Cecil Westerhof
Dat was waarom ik aan het truken was.
knoeien
Oscar
2023-11-06 14:05:59 UTC
Permalink
Post by De ongekruisigde
Oeps, belangrijk onderdeel vergeten te noemen. 🥵
set -o errexit
Oh, aha. Dan snap ik je probleem.
Post by De ongekruisigde
https://stackoverflow.com/questions/44080974/if-errexit-is-on-how-do-i-run-a-command-that-might-fail-and-get-its-exit-code
Dit is zowaar een bruikbare tip van De ongekruisigde.

Maar nou is mijn vraag: heb je retVal echt nodig, ook als het goed gaat?

Zou je het zelfs zonder retVal afkunnen met deze leesbaardere
constructie:

if sa-update
then
# doe wat nodig is als sa-update goed gaat
else
# doe de foutafhandeling
fi

Jouw eerdere 'sa-update && retVal=0 || retVal=$?' zou je ook zo kunnen
schrijven:

if sa-update
then
retVal=0
else
retVal=$?
fi

En dat is eigenlijk net zo'n rare work-around. En al helemaal als je 2
keer 'retVal=$?' schijft, ook waar die altijd 0 zal zijn.
--
[J|O|R] <- .signature.gz
Cecil Westerhof
2023-11-06 16:03:35 UTC
Permalink
Post by Oscar
Post by De ongekruisigde
Post by Cecil Westerhof
Oeps, belangrijk onderdeel vergeten te noemen. 🥵
set -o errexit
Oh, aha. Dan snap ik je probleem.
Post by De ongekruisigde
https://stackoverflow.com/questions/44080974/if-errexit-is-on-how-do-i-run-a-command-that-might-fail-and-get-its-exit-code
Dit is zowaar een bruikbare tip van De ongekruisigde.
Maar nou is mijn vraag: heb je retVal echt nodig, ook als het goed gaat?
Yep, want er komt een hele lap code na die er gebruik van maakt.
Post by Oscar
Zou je het zelfs zonder retVal afkunnen met deze leesbaardere
if sa-update
then
# doe wat nodig is als sa-update goed gaat
else
# doe de foutafhandeling
fi
Jouw eerdere 'sa-update && retVal=0 || retVal=$?' zou je ook zo kunnen
if sa-update
then
retVal=0
else
retVal=$?
fi
En dat is eigenlijk net zo'n rare work-around. En al helemaal als je 2
keer 'retVal=$?' schijft, ook waar die altijd 0 zal zijn.
Ik heb er al van gemaakt:
if sa-update ; then retVal=0 ; else retVal=${?} ; fi
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
Oscar
2023-11-06 16:36:56 UTC
Permalink
Post by Cecil Westerhof
Post by Oscar
Maar nou is mijn vraag: heb je retVal echt nodig, ook als het goed gaat?
Yep, want er komt een hele lap code na die er gebruik van maakt.
En die code kan niet simpelweg tussen de 'else' en 'fi'? Of als je het
omkeert:

if ! sa-update
then
: doe de dingen die je doet als het fout ging
else
: doe iets met de resultaten van de update
fi
: ga verder met het script


Of een hele andere invalshoek:

errors=0

sa-update || : $((errors++))
nog-iets || : $((errors++))
iets-anders || : $((errors++))

echo Aantal fouten: ${errors}

Hier gebruik je de : om precies niks te doen met de argumenten. Bash zal
die argumenten wel evalueren, met een increment van ${errors} tot gevolg.

Wordt allemaal niet veel leesbaarder. Ik weet niet of dat een doel is?
Post by Cecil Westerhof
if sa-update ; then retVal=0 ; else retVal=${?} ; fi
Ah. Nee dus. ;-)

De reden waarom je het zelf ook al niet fijn vindt om te lezen is omdat
het inderdaad onlogische code is. Snap je dit nog als je over een paar
jaar iets moet aanpassen? Zal een collega of opvolger deze "overbodige"
construcite weg willen optimaliseren, met dramatische gevolgen?
--
[J|O|R] <- .signature.gz
Cecil Westerhof
2023-11-06 17:58:36 UTC
Permalink
Post by Oscar
Post by Cecil Westerhof
Post by Oscar
Maar nou is mijn vraag: heb je retVal echt nodig, ook als het goed gaat?
Yep, want er komt een hele lap code na die er gebruik van maakt.
En die code kan niet simpelweg tussen de 'else' en 'fi'? Of als je het
if ! sa-update
then
: doe de dingen die je doet als het fout ging
else
: doe iets met de resultaten van de update
fi
: ga verder met het script
Nope, een 'foutcode' wordt gebruikt om een status terug te geven. Aan
de hand van de status code (inclusief 0) moeten dingen worden gedaan.
Het zou eventueel wel kunnen, maar het maakt de leesbaarheid er niet
beter op.
Post by Oscar
Wordt allemaal niet veel leesbaarder. Ik weet niet of dat een doel is?
Vind ik zelfs belangrijker dan performance.
Post by Oscar
Post by Cecil Westerhof
if sa-update ; then retVal=0 ; else retVal=${?} ; fi
Ah. Nee dus. ;-)
De reden waarom je het zelf ook al niet fijn vindt om te lezen is omdat
het inderdaad onlogische code is. Snap je dit nog als je over een paar
jaar iets moet aanpassen? Zal een collega of opvolger deze "overbodige"
construcite weg willen optimaliseren, met dramatische gevolgen?
Het is in i.i.g. een stuk leesbaarder dan de originele variant.
En heb ook erboven gezet:
# Need the return value of sa-update
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
Oscar
2023-11-07 10:25:02 UTC
Permalink
Post by Cecil Westerhof
Nope, een 'foutcode' wordt gebruikt om een status terug te geven.
duh
Post by Cecil Westerhof
Aan de hand van de status code (inclusief 0) moeten dingen worden
gedaan. Het zou eventueel wel kunnen, maar het maakt de leesbaarheid
er niet beter op.
Ik vraag me af hoe leesbaar 'retVal' is als je de afhandeling pas heel
veel verderop in het script doet. Maar mogelijk gebruik je daar een
zinniger naam?

Mijn aanpak zou waarschijnlijk zoiets zijn in een groter script:

# initialisatie
do_install_updates=yes

# [...]

# download updates
if ! sa-update; then
log_error "sa-update failed with exit code $?"
do_install_updates=no
fi

# [...]

# optionele extra tests
if ! check_disk_space $SIZE_NEEDED
log_error "Insufficient disk space; not installing updates"
do_install_updates=no
fi

# [...]

# install time!
if [ $do_install_updates == yes ]; then
install_updates
fi

Maar nu doe ik heel veel aannames over de flow in je script. ;-)
Post by Cecil Westerhof
Het is in i.i.g. een stuk leesbaarder dan de originele variant.
# Need the return value of sa-update
Deze comment heeft ook een 100% match met:

sa-update
retVal=$?

Suggestie:

# Need to catch errors from sa-update because of -o errexit

Dat zou mij in ieder geval in het handboek doen kijken als ik niet weet
wat '-e' of '-o errexit' precies doet. Ook als de 'set -o errexit' meer
dan een schermvol van de code geleden is, dan kan is dit een nuttige
reminder.

Maar we dwalen af. Je vraag is beantwoord. Het was geen request for
comments op je coding style... ;-)
--
[J|O|R] <- .signature.gz
Cecil Westerhof
2023-11-07 14:18:40 UTC
Permalink
Post by Oscar
Ik vraag me af hoe leesbaar 'retVal' is als je de afhandeling pas heel
veel verderop in het script doet. Maar mogelijk gebruik je daar een
zinniger naam?
Naam is zeker niet de beste. (Code van tien jaar terug.) Maar hij
wordt ook meteen gebruikt:
# Need the return value of sa-update
if sa-update --debug 2>${_log_file} ; then retVal=0 ; else retVal=${?} ; fi
case ${retVal} in
0)
echo "Updated SpamAssassin rules"
systemctl restart spamd
;;
1)
echo "There where no updates for SpamAssassin rules"
;;
2)
.
.
.
Post by Oscar
Post by Cecil Westerhof
Het is in i.i.g. een stuk leesbaarder dan de originele variant.
# Need the return value of sa-update
sa-update
retVal=$?
# Need to catch errors from sa-update because of -o errexit
Dat zou mij in ieder geval in het handboek doen kijken als ik niet weet
wat '-e' of '-o errexit' precies doet. Ook als de 'set -o errexit' meer
dan een schermvol van de code geleden is, dan kan is dit een nuttige
reminder.
Dat is wel een goede: nu gaat het teveel van mij uit. Kans is niet
groot dat anderen deze code gaan lezen, maar je weet het maar nooit.
En het voorkomt dat ik hetzelfde doe bij andere code die wel door
anderen wordt gebruikt.
Post by Oscar
Maar we dwalen af. Je vraag is beantwoord. Het was geen request for
comments op je coding style... ;-)
Och, ik vind het nooit erg om dingen beter te leren doen. :-D


Nog een kleine aanvulling.
Er stond al jaren:
set +o errexit
sa-update --debug 2>${_log_file}
retVal=${?}
set -o errexit

Maar dat vond ik om meerdere reden niet mooi. Mijn grootste probleem
ermee was dat er wordt aangenomen dat errexit aanstaat. En dat zal in
dit programma ook zo zijn, maar ik kan me voorstellen dat het niet in
alle scripts zo zal zijn.
Vandaar dat ik eindelijk de stoute schoenen heb aangetrokken. ;-P
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
Oscar
2023-11-07 17:36:55 UTC
Permalink
Post by Cecil Westerhof
Post by Oscar
Ik vraag me af hoe leesbaar 'retVal' is als je de afhandeling pas heel
veel verderop in het script doet. Maar mogelijk gebruik je daar een
zinniger naam?
Naam is zeker niet de beste. (Code van tien jaar terug.) Maar hij
# Need the return value of sa-update
if sa-update --debug 2>${_log_file} ; then retVal=0 ; else retVal=${?} ; fi
case ${retVal} in
0)
echo "Updated SpamAssassin rules"
systemctl restart spamd
;;
1)
echo "There where no updates for SpamAssassin rules"
;;
2)
.
.
.
Zou dit werken?

if sa-update --debug 2> ${_log_file}
then
echo "Updated SpamAssassin rules"
systemctl restart spamd
sa_result=0
else
sa_result=$?
case ${sa_result} in
0)
echo "Hoe zijn we hier terecht gekomen?"
exit 42
;;
1)
echo "There where no updates for...."
;;
.
.
.
esac
fi

Je ziet hier ook een persoonlijke voorkeur van mij om de 'then' op de
volgende regel te schrijven ipv '; then' aan het einde van de regel.
Post by Cecil Westerhof
Nog een kleine aanvulling.
set +o errexit
sa-update --debug 2>${_log_file}
retVal=${?}
set -o errexit
Maar dat vond ik om meerdere reden niet mooi. Mijn grootste probleem
ermee was dat er wordt aangenomen dat errexit aanstaat. En dat zal in
dit programma ook zo zijn, maar ik kan me voorstellen dat het niet in
alle scripts zo zal zijn.
Je zou het in een subshell kunnen stoppen:

set -o errexit # of niet
.
.
.
(
set +o errexit
sa-udpate --debug 2> ${_log_file}
retVal=$?
)
.
.
.

Maar het grote nadeel is hier dat je retVal buiten de subshell weer
kwijt bent. Daar heb je dus niks aan als je er later wat mee wil.

En oh ja, de subshell heeft ook een exitcode. Als die niet 0 is, zal je
parent shell alsnog de errexit triggeren. Waardeloos advies dus. ;-)
--
[J|O|R] <- .signature.gz
Cecil Westerhof
2023-11-06 15:09:07 UTC
Permalink
Post by De ongekruisigde
Post by Cecil Westerhof
Post by Richard Lucassen
On Sun, 05 Nov 2023 22:56:24 +0100
Post by Cecil Westerhof
Ik heb een oplossing gevonden, maar ik ben nog steeds benieuwd naar
het verschil bij de bovenstaande commando's.
sa-update && retVal=${?} || retVal=${?}
sa-update
EXITCODE=$?
<verdere code>
echo "de exitcode van sa-update is ${EXITCODE}"
M.a.w.: stop de exitcode direct in een var. Dan raak je die niet meer
kwijt. Dan vang je ook meteen alle andere exitcodes (dus niet 0 of 1)
af, zoals bij wget of rsync.
Oeps, belangrijk onderdeel vergeten te noemen. 🥵
set -o errexit
https://stackoverflow.com/questions/44080974/if-errexit-is-on-how-do-i-run-a-command-that-might-fail-and-get-its-exit-code
Daar heb ik bovenstaande oplossing vandaan. :-)

Maar dit is misschien een betere oplossing (duidelijker):
if sa-update ; then retVal=0 ; else retVal=${?} ; fi

Eigenlijk heb ik een grondige hekel aan 1-regelige if statements, maar
in dit specifieke geval ben ik bereid een uitzondering te maken.
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
De ongekruisigde
2023-11-06 15:17:56 UTC
Permalink
Post by Cecil Westerhof
Post by De ongekruisigde
Post by Cecil Westerhof
Post by Richard Lucassen
On Sun, 05 Nov 2023 22:56:24 +0100
Post by Cecil Westerhof
Ik heb een oplossing gevonden, maar ik ben nog steeds benieuwd naar
het verschil bij de bovenstaande commando's.
sa-update && retVal=${?} || retVal=${?}
sa-update
EXITCODE=$?
<verdere code>
echo "de exitcode van sa-update is ${EXITCODE}"
M.a.w.: stop de exitcode direct in een var. Dan raak je die niet meer
kwijt. Dan vang je ook meteen alle andere exitcodes (dus niet 0 of 1)
af, zoals bij wget of rsync.
Oeps, belangrijk onderdeel vergeten te noemen. 🥵
set -o errexit
Misschien is een shell script linter een beter idee dan die errexit?

https://blog.davidjeddy.com/2018/11/27/using-shellcheck-to-lint-your-bash-sh-scripts/
Post by Cecil Westerhof
Post by De ongekruisigde
https://stackoverflow.com/questions/44080974/if-errexit-is-on-how-do-i-run-a-command-that-might-fail-and-get-its-exit-code
Daar heb ik bovenstaande oplossing vandaan. :-)
if sa-update ; then retVal=0 ; else retVal=${?} ; fi
Eigenlijk heb ik een grondige hekel aan 1-regelige if statements, maar
in dit specifieke geval ben ik bereid een uitzondering te maken.
mij staat vooral dat tweemaal toekennen aan retVal tegen, een
non-problem wat alleen door die errexit noodzakelijk is
Oscar
2023-11-06 15:53:28 UTC
Permalink
Post by Cecil Westerhof
if sa-update ; then retVal=0 ; else retVal=${?} ; fi
Eigenlijk heb ik een grondige hekel aan 1-regelige if statements, maar
in dit specifieke geval ben ik bereid een uitzondering te maken.
# variatie 1:
# subproces met stdout naar retVal

retVal=$(sa-update > /dev/null 2>&1; echo $?)

# variatie 2:
# retVal initialiseren en bij een fout aanpassen

retVal=0
sa-update || retVal=$?

# variatie 3:
# sa-update in de achtergrond draaien en
# met wait de exitcode opvangen

sa-update & wait
retVal=$?


Allemaal niet heel mooi. En dat allemaal omdat je die errexit zo graag
wil gebruiken. Meestal doe je dat als je zelf geen error-handling wil
doen, maar ook niet wil dat je script na een onverwachte fout door
blijft denderen. Hier wil je dus wel error-handling doen en dan kom je
dus in de knoop.

Misschien moet je je afvragen of het niet verstandiger is om die externe
aanroepen te draaien in een sectie van het script waar 'errexit' uit staat.

Hoe gebruik je die retVal verder? Is daar nog wat om heen te bouwen met
een mooiere if-constructie? Het kan wel eens veel leesbaarder worden
eerlijk gezegd. Net zoals de hint om niet : maar true te gebruiken.
--
[J|O|R] <- .signature.gz
De ongekruisigde
2023-11-06 09:42:22 UTC
Permalink
Post by Cecil Westerhof
Post by Cecil Westerhof
echo ${?}
1
echo ${?}
0
sa-update
echo ${?}
1
Waarom wordt in het eerste geval de foutcode wel bewaard en in het
tweede geval niet?
Ik heb een oplossing gevonden, maar ik ben nog steeds benieuwd naar
het verschil bij de bovenstaande commando's.
weet je dat echt niet? ( hint: tik eens which true )
Post by Cecil Westerhof
sa-update && retVal=${?} || retVal=${?}
dat is een lelijke workaround voor een non-problem
Oscar
2023-11-06 13:47:34 UTC
Permalink
Post by De ongekruisigde
Post by Cecil Westerhof
Ik heb een oplossing gevonden, maar ik ben nog steeds benieuwd naar
het verschil bij de bovenstaande commando's.
weet je dat echt niet? ( hint: tik eens which true )
Wat een ontzettend nutteloos en ook nog eens fout antwoord.

Wat heeft het pad naar 'true' te maken met zijn probleem?
Leg dat eens uit?
--
[J|O|R] <- .signature.gz
De ongekruisigde
2023-11-06 15:05:39 UTC
Permalink
Post by Oscar
Post by De ongekruisigde
Post by Cecil Westerhof
Ik heb een oplossing gevonden, maar ik ben nog steeds benieuwd naar
het verschil bij de bovenstaande commando's.
weet je dat echt niet? ( hint: tik eens which true )
Wat een ontzettend nutteloos en ook nog eens fout antwoord.
Nou... Als je niet beseft dat : voor true staat en dat true
gewoon een commando is dat in een waarde in ${?} resulteert dan
zou je misschien op het spoor van Cecil eindigen. Kortom: niet
fout maar simpelweg een hint (die je wel degelijk op het goede
spoor zou kunnen zetten).
Post by Oscar
Wat heeft het pad naar 'true' te maken met zijn probleem?
Leg dat eens uit?
Niet het pad naar true maar het feit dat je uit het bestaan van
dat pad kan afleiden true geen shell built-in is maar een extern
commando dat een resultaat code in ${?} zet. Enigszins cryptisch
misschien maar komaan zeg, welk niveau heeft men hier (*)?


(*) uit jouw uitleg in een ander antwoord leid ik af dat jij in
deze wel weet waarover je 't hebt.
Oscar
2023-11-06 15:31:23 UTC
Permalink
Post by De ongekruisigde
Post by Oscar
Post by De ongekruisigde
weet je dat echt niet? ( hint: tik eens which true )
Wat een ontzettend nutteloos en ook nog eens fout antwoord.
Nou... Als je niet beseft dat : voor true staat en dat true
gewoon een commando is dat in een waarde in ${?} resulteert dan
zou je misschien op het spoor van Cecil eindigen.
Waarom zou `which true` Cecil op het spoor kunnen brengen?

Met 'which' zoek je via het pad naar 'true' waardoor je uitkomt
op /bin/true. Dat is een externe executable die interdaad niet veel meer
doet dan een 0 als exit value. Dit in tegenstelling tot de : wat een
shell builtin van bash is. Net als 'true' trouwens. Kijk maar eens wat
'type true' oplevert.

Net als bijvoorbeeld echo heb je dus twee varianten. De builtin van bash
(die je krijgt als je 'echo' zonder pad gebruikt) en /bin/echo.

Maar dan komen we bij ':'. Jij zegt dat nu dat voor true staat, maar dat
klopt ook al niet, hoewel dat meer een semantische kwestie is. Kijk maar:

$ help true
true: true
Return a successful result.

Exit Status:
Always succeeds.

$ help :
:: :
Null command.

No effect; the command does nothing.

Exit Status:
Always succeeds.

Zoals je ziet heeft 'true' een functie. Het returned expliciet 'Success'.
De : daarentegen is een 'null command', dat altijd succesvol afloopt.

Het effect is hetzelfde. Cecil had dus ook 'sa-update || true' kunnen
schrijven. Ik vind zelfs dat dat minder cryptisch is, dus beter.

Maar dan nog. Zelfs al zou enige variant /bin/true aanroepen, dan nog
was dat niet het antwoord op de vraag waarom de resultaten verschillen.

Het enige juiste antwoord heb ik daarnet gegeven. Het verschil komt
doordat bash zelf al een fout geeft op het evalueren van $((1/0))
voordat de regel uitgevoerd kan worden.

Daar verandert geen 'which /bin/true' iets aan.
Post by De ongekruisigde
Niet het pad naar true maar het feit dat je uit het bestaan van
dat pad kan afleiden true geen shell built-in is maar een extern
commando dat een resultaat code in ${?} zet. Enigszins cryptisch
misschien maar komaan zeg, welk niveau heeft men hier (*)?
Het is dus niet eens een extern commando. En de hint leidt af van het
werkelijke probleem. Ook al vervang je alle dubbele punten door
/bin/true, dan nog krijg je het merkwaardige verschil tussen beide
varianten.
Post by De ongekruisigde
(*) uit jouw uitleg in een ander antwoord leid ik af dat jij in
deze wel weet waarover je 't hebt.
Dank. :-)
--
[J|O|R] <- .signature.gz
De ongekruisigde
2023-11-06 15:47:38 UTC
Permalink
Post by Oscar
Post by De ongekruisigde
Post by Oscar
Post by De ongekruisigde
weet je dat echt niet? ( hint: tik eens which true )
Wat een ontzettend nutteloos en ook nog eens fout antwoord.
Nou... Als je niet beseft dat : voor true staat en dat true
gewoon een commando is dat in een waarde in ${?} resulteert dan
zou je misschien op het spoor van Cecil eindigen.
Waarom zou `which true` Cecil op het spoor kunnen brengen?
Met 'which' zoek je via het pad naar 'true' waardoor je uitkomt
op /bin/true. Dat is een externe executable die interdaad niet veel meer
doet dan een 0 als exit value. Dit in tegenstelling tot de : wat een
shell builtin van bash is. Net als 'true' trouwens. Kijk maar eens wat
'type true' oplevert.
Net als bijvoorbeeld echo heb je dus twee varianten. De builtin van bash
(die je krijgt als je 'echo' zonder pad gebruikt) en /bin/echo.
Maar dan komen we bij ':'. Jij zegt dat nu dat voor true staat, maar dat
$ help true
true: true
Return a successful result.
Always succeeds.
Null command.
No effect; the command does nothing.
Always succeeds.
Zoals je ziet heeft 'true' een functie. Het returned expliciet 'Success'.
De : daarentegen is een 'null command', dat altijd succesvol afloopt.
Dan doet het dus wel iets! Namelijk het op 0 zetten van de
resultaat code in ${?} wat niet 'null' genoemd kan worden. Een
Post by Oscar
Het effect is hetzelfde. Cecil had dus ook 'sa-update || true' kunnen
schrijven. Ik vind zelfs dat dat minder cryptisch is, dus beter.
ik ook
Post by Oscar
Maar dan nog. Zelfs al zou enige variant /bin/true aanroepen, dan nog
was dat niet het antwoord op de vraag waarom de resultaten verschillen.
als je die deling door 0 even buiten beschouwing laat dan heb heb
je nog steeds een vraag met twee mogelijkheden in de resultaten,
waarop ik antwoord heb gegeven (hoewel niet geheel kloppend, blijkt)
Post by Oscar
Het enige juiste antwoord heb ik daarnet gegeven. Het verschil komt
doordat bash zelf al een fout geeft op het evalueren van $((1/0))
voordat de regel uitgevoerd kan worden.
dat is een heel ander verhaal waar ik niet eens op ben ingegaan
Post by Oscar
Daar verandert geen 'which /bin/true' iets aan.
dat heb ik ook niet geschreven
Post by Oscar
Post by De ongekruisigde
Niet het pad naar true maar het feit dat je uit het bestaan van
dat pad kan afleiden true geen shell built-in is maar een extern
commando dat een resultaat code in ${?} zet. Enigszins cryptisch
misschien maar komaan zeg, welk niveau heeft men hier (*)?
Het is dus niet eens een extern commando. En de hint leidt af van het
werkelijke probleem. Ook al vervang je alle dubbele punten door
/bin/true, dan nog krijg je het merkwaardige verschil tussen beide
varianten.
ik had die : nog nooit gebruikt dus enige onbekendheid daarmee
heb ik mijzelf ondertussen al vergeven
Post by Oscar
Post by De ongekruisigde
(*) uit jouw uitleg in een ander antwoord leid ik af dat jij in
deze wel weet waarover je 't hebt.
zie je wel ;-)
Post by Oscar
Dank. :-)
Oscar
2023-11-06 16:05:42 UTC
Permalink
Post by De ongekruisigde
Dan doet het dus wel iets! Namelijk het op 0 zetten van de
resultaat code in ${?} wat niet 'null' genoemd kan worden.
Officieel doet het niks! En dat heel succesvol, dus returned het geen
error maar success. True zet expliciet de exitwaarde op 'Success'.

Moraal van dit verhaal: Als je true wil hebben, vraag dan om true.
Post by De ongekruisigde
ik had die : nog nooit gebruikt dus enige onbekendheid daarmee
heb ik mijzelf ondertussen al vergeven
Ik gebruik hem wel eens een enkele keer als 'nop' statement. Zoals je in
python wel eens 'pass' gebruikt.

De laatste keer dat ik hem gebruikte was om in de .bash_history aan te
geven wat ik aan het doen was, wetende dat er een grote kans is dat een
ander later mee zou kijken in die history. Een # komt niet in de history,
maar dit wel:

: uitleg wat ik ga doen
complex commando
nogeen commando
: resultaat was - iets
vervolgens een commando met 'iets'
exit

In deze specifieke situatie was dat even heel handig...

Maar het gebruik als alternatief voor 'true' deed mijn wenkrbouwen ook
wel even wat spierpijn. Vooral omdat ik er in eerste instantie falikant
overheen las. Dus Cecil: please! ;-)
--
[J|O|R] <- .signature.gz
Oscar
2023-11-06 13:50:16 UTC
Permalink
Post by Cecil Westerhof
sa-update && retVal=${?} || retVal=${?}
De oplossing voor welk probleem was dat dan?

Dit werkt net zo goed:

sa-update
retVal=$?

Of als je het graag in 1 regel wil:

sa-update; retVal=$?
--
[J|O|R] <- .signature.gz
Cecil Westerhof
2023-11-06 15:15:01 UTC
Permalink
Post by Oscar
Post by Cecil Westerhof
sa-update && retVal=${?} || retVal=${?}
De oplossing voor welk probleem was dat dan?
Dat ik in eigenlijk al mijn script heb:
set -o errexit

En ik moet de return code van sa-update hebben en voorkomen dat mijn
script wordt getermineerd als die niet 0 is.
Post by Oscar
sa-update
retVal=$?
sa-update; retVal=$?
Nope, maar dit wel (denk beter als de eerdere):
if sa-update ; then retVal=0 ; else retVal=${?} ; fi
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
Oscar
2023-11-06 13:44:28 UTC
Permalink
Post by Cecil Westerhof
echo ${?}
Waarom "of niks" er achter? 'help :' zegt dat die laatste altijd true
returned, dus je zou verwachten dat die 'echo $?' altijd 0 geeft.

Maar!

De shell ziet een '||' met twee commando's er omheen. Voordat hij de
commando's kan uitvoeren, moet ie eerst de regel evalueren. Bij dat
evalueren gaat het al hartstikke fout, want je deelt daarbij door 0.

De hele regel is dus niet eens aan het uitvoeren toegekomen. Kijk maar
eens wat er gebeurt als je

foobar $((1/0))

uitvoert. Je zou misschien verwachten:

foobar: command not found

maar je krijgt:

bash: 1/0: division by 0 (error token is "0")

Leermoment: de evaluatie van de regel gebeurt in de huidige shell,
voordat de regel uitgevoerd wordt. Het is dus niet 'echo' die in je
voorbeeld een fout returnt, het is bash die op zijn bek gaat.
Post by Cecil Westerhof
1
Klopt. Het uitvoeren van de voorgaande regel heeft een foutcode gezet.
Post by Cecil Westerhof
echo ${?}
0
Ook dat klopt. Als 'sa-update' zelf 0 terug had gegeven, dan is de regel
klaar en is je $? gezet door sa-update. Als die echter een error had
gegeven, dan was het tweede deel van de 'or' uitgevoerd. Daar heb je een
':' staan wat altijd 0 returned. Zie 'help :' in bash. De $? in je echo
komt dan van de : vandaan. Je krijgt dus altijd 0.

Voor wie het nog niet weet, maar wel ervaring heeft in andere talen: In
bash betekend 0 hetzelfde als True en non-zero is dan False. De 0 staat
simpelweg voor: "Geen fout" of "Succes". De booleanse logica blijft
verder hetzelfde.
Post by Cecil Westerhof
sa-update
echo ${?}
1
Dan zal sa-update een exitcode van 1 hebben gehad. Heel logisch. ;-)

Ik snap eigenlijk niet helemaal waarom je de accolades om de ? heen zet.
Het mag, maar het lijkt mij hier overbodig en ietwat verwarrend.
--
[J|O|R] <- .signature.gz
Cecil Westerhof
2023-11-06 15:22:35 UTC
Permalink
Post by Oscar
Post by Cecil Westerhof
echo ${?}
Waarom "of niks" er achter? 'help :' zegt dat die laatste altijd true
returned, dus je zou verwachten dat die 'echo $?' altijd 0 geeft.
Maar!
De shell ziet een '||' met twee commando's er omheen. Voordat hij de
commando's kan uitvoeren, moet ie eerst de regel evalueren. Bij dat
evalueren gaat het al hartstikke fout, want je deelt daarbij door 0.
De hele regel is dus niet eens aan het uitvoeren toegekomen. Kijk maar
eens wat er gebeurt als je
foobar $((1/0))
foobar: command not found
bash: 1/0: division by 0 (error token is "0")
Leermoment: de evaluatie van de regel gebeurt in de huidige shell,
voordat de regel uitgevoerd wordt. Het is dus niet 'echo' die in je
voorbeeld een fout returnt, het is bash die op zijn bek gaat.
Post by Cecil Westerhof
1
Klopt. Het uitvoeren van de voorgaande regel heeft een foutcode gezet.
Post by Cecil Westerhof
echo ${?}
0
Ook dat klopt. Als 'sa-update' zelf 0 terug had gegeven, dan is de regel
klaar en is je $? gezet door sa-update. Als die echter een error had
gegeven, dan was het tweede deel van de 'or' uitgevoerd. Daar heb je een
':' staan wat altijd 0 returned. Zie 'help :' in bash. De $? in je echo
komt dan van de : vandaan. Je krijgt dus altijd 0.
Bedankt voor de heldere uitleg.

Was de 'oplossing' op het internet tegengekomen, maar het was dus geen
oplossing.
Post by Oscar
Ik snap eigenlijk niet helemaal waarom je de accolades om de ? heen zet.
Het mag, maar het lijkt mij hier overbodig en ietwat verwarrend.
Doe ik al heel lang omdat i.i.g. vroeger het zo was dat als je
gebruikte:
echo $pietjePuk

en de variabele pietjePuk niet bestond, maar pietje wel, dat je dan de
waarde kreeg in pietje met Puk erachter i.p.v. een fout, of lege string.

Dat is trouwens niet meer zo zie ik.
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
Oscar
2023-11-06 16:14:53 UTC
Permalink
Post by Cecil Westerhof
Post by Oscar
Ik snap eigenlijk niet helemaal waarom je de accolades om de ? heen zet.
Het mag, maar het lijkt mij hier overbodig en ietwat verwarrend.
Doe ik al heel lang omdat i.i.g. vroeger het zo was dat als je
echo $pietjePuk
en de variabele pietjePuk niet bestond, maar pietje wel, dat je dan de
waarde kreeg in pietje met Puk erachter i.p.v. een fout, of lege string.
Dat is trouwens niet meer zo zie ik.
Zoals je het nu beschrijft, is het nooit geweest. Eerder andersom: Als
je de tekst Puk achter $Pietje wil plakken, dan doe je ${Pietje}Puk.
Met die accolades geef je heel duidelijk aan wat de naam van je
variabele is. Maar veel meer doet het ook niet, zo uit mijn hoofd. Als
de waarde een spatie bevat (of andere gevaarlijke tekens) dan wordt het
niet veiliger door ${PietjePuk} te gebruiken.

Wel snap ik dat je het zou doen als goede gewoonte. Het kan nooit kwaad
om die accolades om een variabele heen te zetten. Maar in het geval van
'$?' hebben we het over een variabele die ALTIJD bestaat en NOOIT een
andere waarde dan een integer getal kan hebben. De accolades zijn dan
niet alleen overbodig, ze leiden de lezer ook af van het feit dat je $?
aan het gebruiken bent. Ik moest in ieder geval twee keer kijken.

Die $? is zo'n standaard idioom, daar moet je niet aanzitten.

Naar mijn bescheiden mening natuurlijk. Andere inzichten zijn welkom.
--
[J|O|R] <- .signature.gz
Loading...