[comp.unix.wizards] Conditional setting of ENV in ksh - Question of how to

rob@pbhyf.PacBell.COM (Rob Bernardo) (08/18/88)

In one of the earlier guides to ksh, I found any interesting way
to set the ENV variable so that your ENV file gets read
only by *interactive* invocations of ksh (which reduces a lot  of
overhead when doing shell escapes and whatnot). The solution
was the following:

export START ENV
START=$HOME/.kshrc		# Name of file with aliases, functions
				# for interactive ksh invocations only
ENV='${START[(_$-=1)+(_=0)-(_$-!=_${-%%*i*})]}'

What I'd like to do is something similar, have ENV set to one file
for interactive ksh invocations and to another file for non-interactive
invocations. But since I can't figure out all that's going on here,
I'm having difficulty.

Even if no one can come up to the solution for having two ENV files,
maybe at least someone can help explain the above way of conditionally
using a single ENV file.

What I understand so far is this. ENV (and also PS1) is unusual in that
it gets evaluated upon *use*. Hence, upon use, that which is inside the
single quotes gets evaluated. This is how I figure it gets evaluated:

1. (_$-=1)  $- contains the flags with which the ksh was invoked,
typically "ism" for interactive shells and "shc" for non-interactive
shell. So this expression sets the variable, either _ism or _shc to
a value of 1 and the value of this whole expression is 1.

2. (_=0)  This expression sets the variable _ to the value of 0, and
the expression has a value of 0.

3. (_$-!=_${-%%*i*}) This expression checks for the inequality of two 
variables.  The left hand side is the variable set in the first of the 
three expressions in ()'s, _blah (where blah stands for whatever were
the invocations flags, typically "ism" or "shc"). The right hand 
side first examines $- and strips it of everything if it contains an 
'i' (the flag that alone really denotes an interactive ksh), which 
means that if the ksh is interactive, the right hand side evalutes to 
_, whose value was set to 0 in the second () expression, otherwise to 
_blah, whose value was set to 1 in the first () expressions. So this
inequality test is true (returns 1) if this is an interactive ksh,
otherwise false (returns 0). 

4. Therefore, if the ksh is interactive the subscript for START is 0 (1+0-1)
otherwise 1 (1+0-0). Since START[0] is defined but START[1] is not
defined, our ENV variable is set to a bona fide file name only if
the ksh is interactive. Voila`!

That much works. One thing I can't figure out is that the third ()
expression seems to get evaluated twice, and I must be wrong about
this. The first time I'm supposing the ${-%%*ism} evaluates the
invocation flags and  takes them away if they contain 'i'. The second
time the variable whose name is _ suffixed with the result of that
pattern substitution undergoes inequality testing.

Okay, so the above works in setting ENV only if the ksh is interactive.
So in order to have different ENV files for interactive and non-interactive
ksh invocations, I figured what I could do this this:

export START ENV
START[0]=$HOME/.kshirc		# Name of file with aliases, functions
				# for interactive ksh invocations only
START[1]=$HOME/.kshnirc		# Name of file with aliases, functions
				# for non-interactive ksh invocations only
ENV='${START[(_$-=1)+(_=0)-(_$-!=_${-%%*i*})]}'


Looks like it should work, but it doesn't! What I find is this:

1. My initial interactive ksh, namely my login shell, works okay,
and ENV has been set to the value of START[0].

2. Any other interactive ksh's, do not work okay. ENV is set to the 
value of START[0], ****but**** the value of START[0] and START[1] have 
been altered!!!! START[0] now has the former value of START[1] and 
START[1] isn't set!

3. And non-interactive ksh's do not have an ENV value, presumably
because, like above, START[1] has been unset.

I fiddled with this more and found that whatever is the highest subscripted
START, it's the one whose value gets copied to START[0] in all non-login
ksh's! This is absolutely bizarre.

So I have two questions:

1. Why are the values of START[x] being altered for subsequent ksh invocations?

2. How do I solve what I originally set out to do -  namely, have ENV
set to one file for all interactive ksh invocations and set to a
different file for all non-interactive ksh invocations?
-- 
Rob Bernardo, Pacific Bell UNIX Small Bus. Systems Development & Maintenance
Email:     ...![backbone]!pacbell!rob   OR  rob@PacBell.COM
Office:    (415) 823-2417  Room 4E750A, San Ramon Valley Administrative Center
Residence: (415) 827-4301  R Bar JB, Concord, California

merlyn@intelob.intel.com (Randal L. Schwartz @ Stonehenge) (08/19/88)

In article <3790@pbhyf.PacBell.COM>, rob@pbhyf (Rob Bernardo) writes:
| 
| In one of the earlier guides to ksh, I found any interesting way
| to set the ENV variable so that your ENV file gets read
| only by *interactive* invocations of ksh (which reduces a lot  of
| overhead when doing shell escapes and whatnot). The solution
| was the following:
[ long details omitted ... ]
| 2. How do I solve what I originally set out to do -  namely, have ENV
| set to one file for all interactive ksh invocations and set to a
| different file for all non-interactive ksh invocations?

Here's what I do:

.profile contains:

	ENV=$HOME/.kshrc; export ENV

$HOME/.kshrc contains:

	. $ENV.host
	case X$- in
	*i* )
		. ${ENV}i
		;;
	*)
		## NON INTERACTIVE SHELL ONLY ##
		;;
	esac

and $HOME/.kshrci contains my interactive shell stuff.  If you added
". ${ENV}u" where it says "NON INTERACTIVE SHELL" above, you could
source your other file instead, calling it "$HOME/.kshrcu".  (I don't
have a need for that, but the hooks are there.)

This stuff is all pretty fast, because the "case" doesn't fork a
shell.  The reason I don't just put the .kshrc stuff in .profile is
that I don't want a /bin/sh to interpret it, just a /bin/ksh.

Hope this helps...
-- 
Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095
on contract to BiiN Technical Publications (for now :-), Hillsboro, Oregon
<merlyn@intelob.intel.com> or ...!tektronix!inteloa[!intelob]!merlyn
Standard disclaimer: I *am* my employer!

ekrell@hector.UUCP (Eduardo Krell) (08/19/88)

In article <3790@pbhyf.PacBell.COM> rob@pbhyf.UUCP writes:

>export START ENV
>START=$HOME/.kshrc		# Name of file with aliases, functions
>				# for interactive ksh invocations only
>ENV='${START[(_$-=1)+(_=0)-(_$-!=_${-%%*i*})]}'

I do it in a more readable way. In my ENV file I have:

case $- in
	*i*) ...
	     ...
esac

Where "..." represents whatever you want your interactive shell
to execute.
This way, you'll execute "..." only when $- (ksh's invocation flags)
contains an "i" (for interactive shell).
    
Eduardo Krell                   AT&T Bell Laboratories, Murray Hill, NJ

UUCP: {att,decvax,ucbvax}!ulysses!ekrell  Internet: ekrell@ulysses.att.com

rob@pbhyf.PacBell.COM (Rob Bernardo) (08/19/88)

In article <10519@ulysses.homer.nj.att.com> ekrell@hector.UUCP (Eduardo Krell) writes:
+I do it in a more readable way. In my ENV file I have:
+
+case $- in
+	*i*) ...
+	     ...
+esac
+
+Where "..." represents whatever you want your interactive shell
+to execute.
+This way, you'll execute "..." only when $- (ksh's invocation flags)
+contains an "i" (for interactive shell).

This is one solution, but like anything, it has its minuses. In this
case the newly spawned ksh has to read the entire file, even the
parts it will never wind  up executing. This can slow things down
quite a bit when doing a simply shell escape, e.g. from vi.

Someone wrote me (Thanks, Doug!) that the reason why the KSHRC array 
(see the orginal posting - too long to repeat it here) gets mangled 
is that ksh cannot correctly pass arrays to its environment. 

In any case,  I came up with a decent solution to the problem. What
I have in my .profile is the following:

ENV='$HOME/.kshrc${-%%[a-hj-z]*}'	# Where to find ksh stuff.
		    # ENV file is .kshrc for non-interactive ksh invocations.
		    # ENV file is .kshrci for interactive ksh invocations.
		    # Presumes i flag is first if it occurs.

(Btw, my .kshrci file has as its first line:
	. .kshrc
so that all the aliases and fuctions in the latter don't need to be
repeated in the former.)
-- 
Rob Bernardo, Pacific Bell UNIX Small Bus. Systems Development & Maintenance
Email:     ...![backbone]!pacbell!rob   OR  rob@PacBell.COM
Office:    (415) 823-2417  Room 4E750A, San Ramon Valley Administrative Center
Residence: (415) 827-4301  R Bar JB, Concord, California

ditto@cbmvax.UUCP (Michael "Ford" Ditto) (08/19/88)

In article <3790@pbhyf.PacBell.COM> rob@pbhyf.PacBell.COM (Rob Bernardo) writes:
>
>In one of the earlier guides to ksh, I found any interesting way
>to set the ENV variable so that your ENV file gets read
>only by *interactive* invocations of ksh (which reduces a lot  of
>overhead when doing shell escapes and whatnot). The solution
>was the following:
>
>export START ENV
>START=$HOME/.kshrc		# Name of file with aliases, functions
>				# for interactive ksh invocations only
>ENV='${START[(_$-=1)+(_=0)-(_$-!=_${-%%*i*})]}'

>Okay, so the above works in setting ENV only if the ksh is interactive.
>So in order to have different ENV files for interactive and non-interactive
>ksh invocations, I figured what I could do this this:
>
>export START ENV
>START[0]=$HOME/.kshirc		# Name of file with aliases, functions
>				# for interactive ksh invocations only
>START[1]=$HOME/.kshnirc		# Name of file with aliases, functions
>				# for non-interactive ksh invocations only
>ENV='${START[(_$-=1)+(_=0)-(_$-!=_${-%%*i*})]}'

>Looks like it should work, but it doesn't! What I find is this:
>
>2. Any other interactive ksh's, do not work okay. ENV is set to the 
>value of START[0], ****but**** the value of START[0] and START[1] have 
>been altered!!!! START[0] now has the former value of START[1] and 
>START[1] isn't set!


This is because you did not give START[] any values in those shells.
Since START was exported by the login shell, it will be inherited by
children as $START, which can also be accessed as $START[0].
$START[1] will not be set.

>I fiddled with this more and found that whatever is the highest subscripted
>START, it's the one whose value gets copied to START[0] in all non-login
>ksh's! This is absolutely bizarre.

It's actually the LAST value that was given to any element of START, not
the highest numbered one.

>2. How do I solve what I originally set out to do -  namely, have ENV
>set to one file for all interactive ksh invocations and set to a
>different file for all non-interactive ksh invocations?

Why not just set your ENV to $HOME/.kshrc or whatever, and in that file
do the checking... like:

case "$-" in
*i*)
	echo "Interactive code goes here"
	;;
*)
	echo "Noninteractive code goes here"
	;;
esac

To make it go faster, have the $ENV file just source one or the other
of two sub-kshrc's.
-- 
					-=] Ford [=-

	.		.		(In Real Life: Mike Ditto)
.	    :	       ,		ford@kenobi.cts.com
This space under construction,		...!ucsd!elgar!ford
pardon our dust.			ditto@cbmvax.commodore.com