Jean Delvare dixit:

>> Do also note that it is not mksh’s goal to clone ksh93 and all of its
>> behaviour, design decisions, etc.
>
>Thank god :-D
>
>This is perfectly understood and accepted, which is why I am asking
>about the intent and your opinion and not bluntly reporting behavioral

OK. (In this case, it’s inherited from pdksh, so there was no intent
from my side on it, but looking at it now it behaves as I’d expect it
to.)

>divergences as bugs. And I keep repeating exactly the same to our
>customers :-) So we are on the same track, no worry.

OK, thanks.

>> The scoping model in ksh93 is fundamentally incompatible to
>> anything you know from anywhere else.
>
>Yeah, the ksh93 variable scoping is... interestingly confusing.

Yeah. They basically have one global and one local scope, and
exchange the latter if a new function is called. This can break
things in interesting ways while also fixing things in intere‐
sting ways…

>> Interesting… so it seems that GNU bash and dash don’t really
>> unset it but only clean it.
>
>Yes and no. See the difference between:
>
>$ foo=
>$ echo foo is ${foo+set}
>foo is set
>
>and:
>
>$ unset foo
>$ echo foo is ${foo+set}
>foo is

Yes, of course; that’s mandated by POSIX.

>So internally bash does make a difference between a variable being null
>and a variable being unset. A bash variable can actually have 4 distinct
>states: non-existent, existent but unset, set but null, and non-null.
>"typeset", "local" and "unset" all put the variable into state
>"existent but unset" (unlike mksh.)

That’s what I meant, sorry for being unclear.

>example above (discovered by accident, doesn't appear to be documented)

No, that’s POSIX sh.

>> >I see that one can use "unset foo[*]" in mksh to achieve the "unset
>> >foo" of other shells. I guess this is a side effect of the
>>
>> You can? Hm, interesting… but makes sense.
>
>Well I found it because it is documented in the man page, but the
>syntax looks odd to me.

The idea being preparing scripts for when we introduce multi-dimensional
arrays, in which there *is* a difference between various sorts of un‐
setting. Probably I needed exactly this: a way to unset all elements of
an array without also removing the array (with its flags like “integer”
or “associative”, the latter also coming some day not soon).

>> if [[ $KSH_VERSION = *@(MIRBSD|LEGACY)\ KSH* ]]; then
>>      function unset {
>>              local __foo
>>
>>              for __foo in "$@"; do
>>                      eval "unset $__foo[*]"
>>              done
>>      }
>> fi
>
>Does that actually work? It doesn't seem like special shell builtins
>can be overloaded with functions, and unset is a special shell builtin.

Ouch. I admit not having tested it. But you can name the function x_unset
and then define an alias. Aliases are parse-time and thus will be used
in favour of builtins of any kind.

>I have to admit I was not sure myself what I would prefer as a script
>author. I cowardly decided that unsetting local variables shouldn't be
>needed, so I did not have to answer the question ;-)

;-)

I’ve not always written nice scripts either. This came with time…
I think 2005 was a turning point for me. That is probably because
that’s when mksh was doing really well and I begun using it for
much more code than before.

>However if I really had to make a choice... My initial feeling was that
>mksh was right, as unset is exactly undoing the effect of typeset. But

Well it’s unsetting the currrently visible instance of that name.
If you have no local, this also unsets the global.

This is needed to implement shell functionality in the shell itself,
e.g. you could write an OOP framework or something with it.

>my second thought was that it makes it way too easy to get things wrong
>and accidentally access global variables. In particular, the fact that
>calling "unset" twice on a local variable actually destroys the global
>variable by the same name is kind of frightening.

True, but this is Unix, we give users the rope to hang themselves.
As long as this is documented… (if it’s not sufficiently documented,
patches are welcome, but I fear this doesn’t really fit into the
manpage’s reference format… maybe adding a FAQ section to it which
would be more tutorial-style (and moving e.g. the Android, OS/2,
read, pipe, etc. stuff there) would be the right thing?)

>In doubt, I guess I would have sticked to what other shells are doing,

I do that quite often (mostly looking at POSIX and ksh93 here), but
in this case I personally don’t have doubt (yet).

>for consistency. Ideally there would be an "unlocal" builtin to achieve
>mksh's "unset" effect in functions.

That goes both against mksh’s minimalist design goals *and* no other
shell has that.

(Another excuse: unset as it’s currently implemented in mksh is easy.
Something like defined-but-unset is harder. Probably would need changes
all over the place, breaking things…)

>But then again I just can't figure out a case where I would first
>declare a local variable and then want to access a global variable by
>the same name instead.

Wrappers in combination with namerefs come to mind.

But the aforementioned code (renamed and with alias) on top of a
script can easily change the behavour script-globally, so this is
easily worked around.

Maybe (after testing…) this could also move into the FAQ…

>There should be no space between mksh and 's.

Thanks, applied… I didn’t catch this because BSD mdoc, in contrast
to GNU’s, did this right already with the No.

bye,
//mirabilos
-- 
Yay for having to rewrite other people's Bash scripts because bash
suddenly stopped supporting the bash extensions they make use of
        -- Tonnerre Lombard in #nosec

Reply via email to