Date:        Fri, 04 Oct 2024 13:43:17 -0700
    From:        "Greg A. Woods" <wo...@planix.ca>
    Message-ID:  <m1swp8x-0036s2C@more.local>

  | To handle the second part of this rule we must compare $0 and $SHELL, as
  | the presence of any operands upon invocation will have changed $0 to
  | something other than $SHELL.

That's not strictly correct, in fact, it fails in perhaps the third most
common way of invoking sh, after just plain "sh", and "sh script", the
next being "sh -c 'commands'"   Additional operands can be given after
the commands in -c case (though it is rarely done) - if not, then $0 is
unchanged (remains the same as it would have been had it been invoked
as just "sh"):

        jacaranda$ sh -c 'echo $0'
        sh

and if the user desires, $0 can be made anything

        jacaranda$ sh -c 'echo $0' anything
        anything

including, kind of obviously, $SHELL :

        jacaranda$ sh -c 'echo $0' "$SHELL"
        /bin/sh

and in that you should compare what $SHELL is with what $0
gets set to, bash does the same thing...

        jacaranda$ echo $SHELL
        /usr/pkg/bin/bash
        jacaranda$ echo $0
        -bash
        jacaranda$ bash -c 'echo $SHELL - $0'
        /usr/pkg/bin/bash - bash
        jacaranda$ bash -c 'echo $SHELL - $0' "$SHELL"
        /usr/pkg/bin/bash - /usr/pkg/bin/bash

Two things of note there, it isn't the shell that is doing
         $0 = basename(argv[0])
(if anything like that were meaningful code, you get the idea)
rather it is login (and probably others)...

This is from login.c:

        (void)setenv("SHELL", pwd->pw_shell, 1);

(and later)

        tbuf[0] = '-';
        (void)strlcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
            p + 1 : pwd->pw_shell, sizeof(tbuf) - 1);

and a bit later:

        execlp(pwd->pw_shell, tbuf, NULL);

That is, argv[0] will only be the same as $SHELL in the very weird
case where pwd->pw_shell has no '/' in its name, and even then, from
login (almost the definition of getting an interactive shell) they
won't be the same, because of the "-" that's prepended.

Further, since $SHELL is (I think always) effectively the full path
of the shell, if you just run

        sh

then argv[0] will be "sh" and "$SHELL" won't be, about the only
time you'll get them to be the same is if you run $SHELL as the
command, as in:

        jacaranda$ $SHELL -c 'echo $0 :: $SHELL'
        /bin/sh :: /bin/sh
or
        jacaranda$ $SHELL -c 'echo $0 :: $SHELL'
        /usr/pkg/bin/bash :: /usr/pkg/bin/bash

(depending which shell is in use).   I don't know about you, but
except when I'm testing a whole bunch of different shells, and
want to be able to paste the exact same command string to all of
them, I almost never actually invoke $SHELL when I mean just sh or bash.

  | Also because of a long-standing "oversight" in NetBSD sh(1) some shells
  | we might ignore the stderr part of the test and just consider stdin (as
  | that's really all that matters for "interactivity", right?).

Depends what your objective is (and what is that "oversight" ??).

If you don't care about getting the correct answer, almost ever, then

  |     if [ -t 0 -a "$0" = "$SHELL" ]; then
  |             sh_is_interactive=true
  |     fi

might work, about 1 time in 50.   And that's ignoring the very real
possibility that test (aka [) might one day just say "test: too many args"
as (ignoring the ']' arg when argv[0] == '[') you have 6 args there, and
test (these days) is only defined to work with a maximum of 4 (and even
with 4, only when the first is '!' - otherwise 3 or less).

In your overall example, you're saved by:

  |     case "$-" in
  |     *i*)
  |             sh_is_interactive=true
  |             ;;
  |     esac

which will work in most shells, and is all that is normally needed.

If you're stuck with a shell where that doesn't work - replace (or fix) it.

That was one of the tenets of the unix design, there can be more
that one command interpreter, and users can use whichever they prefer.
That was truly a novel idea in the early 1970s - the command interpreter
was generally an integral part of the OS before then.   These days,
don't tolerate sub-standard tools, install ones that actually meet
your needs, and use those.

kre

ps: apologies for the long delay before this reply - munnari was down from
last Friday night (here, very early Fri in the US) until Tues morning
(again here) and I am still catching up on NetBSD mailing list(s) mail.


Reply via email to