How to clear $1 when dot-running a script.

Here's my problem: the $1 parameter is getting permanently set when you dot-run a script - and I cannot unset it.

Here's how to duplicate the problem:

1) Create a script called testme and put this simple command in the script:
echo 1=$1

Save the script

2) Make the testme script executable
chmod a+rx testme

3) Now dot-run the script:
. testme

Output:
1=

4)Now dot-run the script with a parameter:
. testme YOU

Output:
1=YOU

5) Now dot-run the script without a parameter:
. testme

Output:
1=YOU

HUH??? There's the problem!!! Why did the script remember the $1 parameter value?

The question is - how do I clear that $1 value???

edit by bakunin: while this is a very interesting question it is hardly related to AIX. I move it over to "Shell programming and scripting" therefore.

I used bash shell and it works exactly fine.the variable $1 is unset.Let me know which shell you use and I can try on it , if I have access to the same.

Thanks!
nua7

Well, you can thank the forum administrator for all the confusion. I originally posted this question in the AIX FORUM since this behavior seemed to be specific to AIX.

I am using KSH shell running on AIX 5.x

First off, I'd like to state for the record, that you should thank yourself instead of thanking me: you haven't made clear that this occurs only in AIX (to your knowledge) and among the many things i am incompetent in is reading minds. Furthermore it will become clear with the answer that i was correct moving the thread as it is indeed a shell-related problem, not a OS-related one. In fact it is a problem of understanding, not of software.

Further, and to clear up the confusion: This effect can probably be demonstrated in other implementations of the Korn Shell too, as it is no bug, but a feature. You execute a script IN THE CURRENT ENVIRONMENT and hence you can set any variable and it will stick to this value until being changed. The same is the case with system variables like $1, which you are setting here - in your current environment. You can query the value of $1 also in the current environment:

# echo $1

# . ./testme xxx
1=xxx
# echo $1
xxx

It may look a bit counter-intuitive, but: which reason would the shell have to change the value of "$1" as long as it isn't being changed?

After this explanation the solution how to clear the variable "$1":

Either provide an empty value to make it empty:

# . ./testme xxx
1=xxx
# echo $1
xxx
# . ./testme ""
1=
# . ./testme
1=

or use "shift" to rotate out $1:

# . ./testme xxx
1=xxx
# echo $1
xxx
# shift
# echo $1

# . ./testme
1=

One word about the implementation of bash: *this* in fact is a bug and the failure of the Linux pdksh to do the same as the AIX ksh should be regarded as sloppiness of implementation, not as feature.

bakunin

Sorry but I disagree. Where is the variable "1" being set? The line "echo 1=$1" does not define or assign any variable. It tells the shell to expand $1 (in this case, XXX) and output "1=XXX"

$ echo ${.sh.version}
Version M 93s+ 2008-01-31
$ cat testme
echo 1=$1
$ . ./testme XXX
1=XXX
$ echo $1

$ . ./testme
1=
$

You are right and wrong, fpmurphy: The variable 1 is not set in the echo-statement. It is merely displayed there. It is set when the script is started and as the script is started in the current environment the variable is set in the current environment.

When you execute "script 1", you start a new shell environment, then set the variable 1 in this environment to "1" and then the script starts to run, yes? If you issue ". script 1" you do not start a new environment but the rest of the procedure occurs quite the same.

bakunin

Good, Bakunin, we agree that the variable "1" is not set by the "echo 1=$1" statement.

You claim that $1 (first positional paramater) should be available in your current environment upon sourcing a file such as in the example provided

Sorry, again, I must disagree. Positional parameters are initially assigned when you invoke a shell, temporarily replaced when a shell function is invoked, and can only be reassigned with the set special built-in command.

$1 is available within the testme script but not outside it. To illustrate this point, try the
following:

#!/usr/bin/ksh
echo "Positional Parameter 1=$1"
. ./testme XXX
echo "Positional Parameter 1=$1"

which gives the following output

$ ./demo FPM
Positional Parameter 1=FPM
1=XXX
Positional Parameter 1=FPM
$

Have you a counter example to disprove my assertion?

ok people, stop fighting over my question...

bakunin - I appologize. I did not "state" that the problem was in AIX, I merely tried to imply it by placing the question in the AIX Forum - and it seems that that still mis-characterizes it since it's really a ksh issue.

I did find an answer to my question - which was

An answer is to use the following:

set -- 

or, as was pointed out earlier by bakunin, use the shift command to shift the positional parameters until they are all empty. For what I am looking for, set -- is more efficient.

Ok - let's lay this out this issue/question a bit better. My issue is that when I am dot-running a script over and over, I don't want the positional parameters to persist in my session. If they do, then I can never re-dot-run the script - or any other script - with NO parameters. In addition, my actual script is scrutinizing the $1 parameter and checking for specific values - so just passing in a "" as the first parameter actual fails my check and spit out a USAGE message explaining how to use the script. The first positional parameter is used to activate optional functions within the script. To just run the script "normally" without the optional features, you don't pass in a parameter.

And there in lies my problem.

The solution for me was to set a Variable=$1 (and repeating that for all other passed in parameters as needed) and immediately issuing set --. This clears all positional parameters that were permanently set for my current environment/session (due to the use of dot-run).

Problem solved.

Now - to address some of the other comments/assertions being made in the other comments/replies posted here:

Here's some new code for testme which shows an example of how I am checking the value of $1 in my "real script" (which I have still not shown you - but we are trying to keep things simple here).

echo 1=$1

if [[ $# > 0 ]]
then
   if [[ ! "${1}" = "DB" ]]
   then
     echo "There was at least 1 Parameter passed into this script and \$1 was not \"DB\". "
   else
     echo "There was at least 1 Parameter passed into this script and \$1 was  \"DB\" "
   fi
else
     echo "There were no parameters passed into this script"
fi

Now run these commands and observe the output.

First, let's clear all positional parameters:

set --

Now let's start our experiment:

. testme
There were no parameters passed into this script

. testme DB
There was at least 1 Parameter passed into this script and $1 was "DB"

. testme
There was at least 1 Parameter passed into this script and $1 was "DB"

The above output shows that $1 persists in the current environment. This is NOT the behavior I need/want.

. testme ""
There was at least 1 Parameter passed into this script and $1 was not "DB"

The above output shows that $1 is not empty and thus fails the test
if [[ ! "${1}" = "DB" ]]
This is NOT the behavior I need.

This also shows that $1 is available in your current environment/session. To further prove this, run the following commands:

. testme DB
There was at least 1 Parameter passed into this script and $1 was "DB"

echo 1=$1
1=DB

The value in $1 would persist and potentially mess with other scripts ONLY when those scripts are dot-run. I hope you would agree that this is NOT a desirable behavior. set -- takes care of that behavior by wiping clean all positional parameters ($1, $2, $3, etc)

First off, I'd like to apologize to fpmurphy and HobieCoop if they had the impression of a fight going on - this is not the case. In fact i'm enjoying tremendously the possibility to gnaw my teeth into a problem which is *not* all-too-obvious to solve.

fpmurphy has raised some interesting points, but i need a bit of time to come up with a (clever) response.

bakunin

HobieCoop, Bakunin and I are not fighting. We are simply trying to come up with a correct understanding of the interesting problem presented to us by you.

And I appreciate it! Thanks for the help! :smiley:

@fmurphy

No counter example needed. Taking your example:

$ uname -a
SunOS db012a 5.8 Generic_117350-35 sun4us sparc FJSV,GPUZC-M
$ echo $0
-ksh
$ . testme
1=
$ . testme YOU
1=YOU
$ . testme
1=YOU
$ ./demo FPM
Positional Parameter 1=FPM
1=XXX
Positional Parameter 1=XXX

However, bash doesn't seem to remember passed positional parameters across dot invocations:

$ cat other
echo "1=$1 2=$2 3=$3 4=$4"
$ bash
$ . other
1= 2= 3= 4=
$ . other a b
1=a 2=b 3= 4=
$ . other z
1=z 2= 3= 4=
$ . other
1= 2= 3= 4=

Ksh on the other hand will reset only when something is passed:

$ ksh
$ . other
1= 2= 3= 4=
$ . other a b
1=a 2=b 3= 4=
$ . other z         # here $2 (and higher) are cleared since at least one positional parameter was passed.
1=z 2= 3= 4=
$ . other
1=z 2= 3= 4=

So in a nutshell, agree with bakunin's points on ksh.

HTH

The AIX ksh behaviour discussed in this thread might be different depending on which ksh version is used to call the dot command. IIRC AIX came with both ksh88 and ksh93 since V5.2. While the ksh93 implementation in AIX was quite buggy (e.g. using it as default login shell could lead to the user being unable to log in) it seems to be usable in the current oslevels.
I assume that most posters used AIX ksh88 (which is still the AIX default shell) for testing. I am unsure about the environment fpmurphy used as

does not look like an AIX ksh93 to me straight away.
However, I am going to point out some difference between the two ksh versions coming with AIX 5L. Ksh versions are identical in the current versions of 5.2 and 5.3. My samples were collected from an AIX 5.3 server.

(0)admin2:/home/shockneck/scripts > oslevel -s
5300-06-06-0811
(0)admin2:/home/shockneck/scripts >

I copied HobieCoop's script from his previous post. I first run the script in ksh88. Mind that the script itself calls /bin/ksh in both tests I am going to do.

(0)admin2:/home/shockneck/scripts > cat testme
#/bin/ksh

echo 1=$1

if [[ $# > 0 ]]
then
   if [[ ! "${1}" = "DB" ]]
   then
     echo "There was at least 1 Parameter passed into this script and \$1 was not \"DB\". "
   else
     echo "There was at least 1 Parameter passed into this script and \$1 was  \"DB\" "
   fi
else
     echo "There were no parameters passed into this script"
fi
(0)admin2:/home/shockneck/scripts >

First the script runs in ksh88 which has not changed in the last years and probably won't in the future.

(1)admin2:/home/shockneck/scripts > Version M-11/16/88f
(130)admin2:/home/shockneck/scripts > set --
(0)admin2:/home/shockneck/scripts > . testme
1=
There were no parameters passed into this script
(0)admin2:/home/shockneck/scripts > . testme DB
1=DB
There was at least 1 Parameter passed into this script and $1 was  "DB"
(0)admin2:/home/shockneck/scripts > . testme
1=DB
There was at least 1 Parameter passed into this script and $1 was  "DB"
(0)admin2:/home/shockneck/scripts >

So this is the test outcome HobieCoop complained about.
Second test, but this time in ksh93 as starting shell

(0)admin2:/home/shockneck/scripts > echo ${.sh.version}
Version M-12/28/93e
(0)admin2:/home/shockneck/scripts > set --
(0)admin2:/home/shockneck/scripts > . testme
1=
There were no parameters passed into this script
(0)admin2:/home/shockneck/scripts > . testme DB
1=DB
There was at least 1 Parameter passed into this script and $1 was  "DB"
(0)admin2:/home/shockneck/scripts > . testme
1=
There were no parameters passed into this script
(0)admin2:/home/shockneck/scripts >

The difference could be considered either a bug or a feature. Regardless using ksh93 would spare HobieCoop from having to flush the whole environment to clear the $1 value.