Today I learned about the “if myfunc” pitfall. I’m pretty fond of shell programming in general, in a punk/lomography kind of way, but that one scares me.
Yeah it comes up on the bash mailing list with some frequency. I think it’s been true for 30 years or more, and every so often there is a big thread about it. Hence “groundhog day”.
Here’s another one (where I participate but so do many other people):
Basically the idea is that idiomatic Oil scripts never look at $? – it’s only used to trigger the errexit rule.
Instead they invoke try and inspect _status when they want to handle errors
Some detail: try is a builtin that takes a block, and every builtin has an exit code.
The exit status of try is always zero, because if it returned a non-zero status for $?, then the errexit rule would trigger, and you wouldn’t be able to handle the error!
So there are no special cases in the interpreter for try.
For context, other builtins that take a Ruby-like block:
cd – save and restore current dir
shopt – save and restore option state
forkwait – “replacement” for subshell ( cd / ; echo $PWD ) which is rarely used in Oil
fork – replacement for &
Generally the errors occur INSIDE the block, not outside, like:
cd /tmp {
cp zzzz / # error happens here
echo done
} # not here
Of course you can nest cd and try if you want.
And the _ convention for _status is for globals / “registers” that the shell itself mutates:
_status, and the rarely used _pipeline_status, _process_sub_status
_match(1) for the match of a regular expression
_this_dir for imports relative to the current directory
Glad it made sense! A related thing that I think will prove useful is that you don’t have to pass a block literal to try. Instead you can pass a variable like
Today I learned about the “if myfunc” pitfall. I’m pretty fond of shell programming in general, in a punk/lomography kind of way, but that one scares me.
Yeah it comes up on the bash mailing list with some frequency. I think it’s been true for 30 years or more, and every so often there is a big thread about it. Hence “groundhog day”.
Here’s another one (where I participate but so do many other people):
https://news.ycombinator.com/item?id=27163494
It’s weird shell folk knowledge.
I add this to my scripts to flag it when run under OSH:
https://github.com/oilshell/oil/blob/master/test/spec.sh#L9
(Right now Oil’s own scripts keep are run under bash as well.)
+1 for
I’ll henceforth use that to explain the essence of shell programming.
why is that?
Good question, I will put this in the FAQ !
Basically the idea is that idiomatic Oil scripts never look at
$?
– it’s only used to trigger theerrexit
rule.Instead they invoke
try
and inspect_status
when they want to handle errorsSome detail:
try
is a builtin that takes a block, and every builtin has an exit code.The exit status of
try
is always zero, because if it returned a non-zero status for $?, then theerrexit
rule would trigger, and you wouldn’t be able to handle the error!So there are no special cases in the interpreter for
try
.For context, other builtins that take a Ruby-like block:
cd
– save and restore current dirshopt
– save and restore option state( cd / ; echo $PWD )
which is rarely used in Oil&
Generally the errors occur INSIDE the block, not outside, like:
Of course you can nest
cd
andtry
if you want.And the
_
convention for_status
is for globals / “registers” that the shell itself mutates:_status
, and the rarely used_pipeline_status
,_process_sub_status
_match(1)
for the match of a regular expression_this_dir
for imports relative to the current directoryRelated questions: https://www.oilshell.org/release/0.10.0/doc/error-handling.html#faq-on-language-design (why is there try but no catch)
Good answer :)
That’s pretty neat, being able to implement this without special cases.
Glad it made sense! A related thing that I think will prove useful is that you don’t have to pass a block literal to
try
. Instead you can pass a variable likeI mentioned this in a thread a few months ago:
https://lobste.rs/s/irvnko/recent_progress_on_oil_shell
I don’t expect this to be common in app code, but I can see it being useful in test frameworks and the like.