Dot sourcing differences in ksh, AIX vs Linux vs Solaris


 
Thread Tools Search this Thread
Top Forums UNIX for Advanced & Expert Users Dot sourcing differences in ksh, AIX vs Linux vs Solaris
# 1  
Old 02-06-2014
Dot sourcing differences in ksh, AIX vs Linux vs Solaris

Why does dot sourcing of ksh functions behave so differently between AIX, Solaris, and Linux? How can I make Linux behave the way I want in the test I show below?

I have a library of interdependent functions I have developed and use in ksh in AIX. They also run in Solaris. Now I am migrating them to Linux. They aren't working properly in Linux. I have devised a test to illustrate the differences. I am looking for an explanation of the behavior, particularly in Linux, and how I can resolve it to be like Solaris (which would be OK) or like AIX (which would be ideal).

Test 1 below is the behavior I like. Test 2 is OK. Test 3 is the one I don't understand and need to fix.

I start by creating this file that contains the "MyFun" function definition in a directory that is on my PATH:
Code:
$ cat MyFun
#! /bin/ksh
print -- "In file MyFun, before def of function MyFun. PID=$$, system=$( uname -rsv )"
function MyFun
{
print -- "In function MyFun. PID=$$, system=$( uname -rsv )"
return $(( $# % 128 )) #number of arguments mod 128
}
print -- "In file MyFun, after def of function MyFun. PID=$$, system=$( uname -rsv )"

The contents above are stored in file "MyFun", which does NOT require execute permissions:
Code:
$ ls -l MyFun | xargs echo | cut -d ' ' -f 1,9 
-rw-r--r-- MyFun

############
TEST 1: run in AIX
(first install MyFun from above into a directory in your PATH, then cd to that directory)

Here when the file is dot sourced a second time, NONE of it executes. The system is caching the dot-sourcing operation, so if this function is shared by several other functions that dot source it and all are used in a script, it only executes once.

The important thing is that the inner part of the function never executes when the file is dot sourced (the function itself doesn't get called during dot sourcing). In this case the behavior is like an import (not include) statement, and is the behavior I want:
Code:
$ #dot source the file first time
$ . MyFun
In file MyFun, before def of function MyFun. PID=8908866, system=AIX 3 5
In file MyFun, after def of function MyFun. PID=8908866, system=AIX 3 5
$ #call the function after dot sourcing
$ MyFun
In function MyFun. PID=8908866, system=AIX 3 5
$ #dot source the file a second time
$ . MyFun
#(there is no output from the command above).

############
TEST 2: run in Solaris (first install MyFun from above)
(first install MyFun from above into a directory in your PATH, then cd to that directory)

Here when the file is dot sourced a second time, the file executes again just like the first time. The system is re-executing the entire file each time it is dot sourced, so if this function is shared by several other functions that dot source it and all are used in a script, the file re-executes every time and the function itself is redundantly redefined each time.

The important thing is that the inner part of the function still never executes when the file is dot sourced (the function itself doesn't get called during dot sourcing). This behaves like an include (not import) statement, and is inefficient compared to test 1, but still works:
Code:
$ #dot source the file first time
$ . MyFun
In file MyFun, before def of function MyFun. PID=29760, system=SunOS 5.10 Generic_141444-09
In file MyFun, after def of function MyFun. PID=29760, system=SunOS 5.10 Generic_141444-09
$ #call the function after dot sourcing
$ MyFun
In function MyFun. PID=29760, system=SunOS 5.10 Generic_141444-09
$ #dot source the file a second time
$ . MyFun
In file MyFun, before def of function MyFun. PID=29760, system=SunOS 5.10 Generic_141444-09
In file MyFun, after def of function MyFun. PID=29760, system=SunOS 5.10 Generic_141444-09

############
TEST 3: run in Linux (first install MyFun from above into a directory in your PATH, then cd to that directory)

Here when the file is dot sourced a second time, the FUNCTION BODY executes even though I don't want to CALL it.

The problem here is that the inner part of the function executes when the file is dot sourced after the first time (the function itself gets called during subsequent dot sourcing operations). I do not understand this behavior and it is harmful:
Code:
$ #dot source the file first time
$ . MyFun
In file MyFun, before def of function MyFun. PID=37604, system=Linux 2.6.32-220.el6.x86_64 #1 SMP Wed Nov 9 08:03:13 EST 2011
In file MyFun, after def of function MyFun. PID=37604, system=Linux 2.6.32-220.el6.x86_64 #1 SMP Wed Nov 9 08:03:13 EST 2011
$ #call the function after dot sourcing
$ MyFun
In function MyFun. PID=37604, system=Linux 2.6.32-220.el6.x86_64 #1 SMP Wed Nov 9 08:03:13 EST 2011
$ #dot source the file a second time
$ . MyFun
In function MyFun. PID=37604, system=Linux 2.6.32-220.el6.x86_64 #1 SMP Wed Nov 9 08:03:13 EST 2011


Last edited by charles_n_may; 02-06-2014 at 05:29 PM.. Reason: clarifying explanations
# 2  
Old 02-06-2014
I think you're using a non-portable function declaration... In some shells that would be a syntax error. This syntax works in any Bourne shell that supports functions AFAIK:

Code:
function () {
        contents
}

This User Gave Thanks to Corona688 For This Post:
# 3  
Old 02-06-2014
RedHat

I want the behavior given by using the function keyword as it is indeed different from that using the parentheses. I use the difference (ksh functions defined with function have their own function environment and my code relies heavily on that isolation, particularly for logging the name of the function, $0, being called), and I am not really interested in bash compatibility.

However I did notice that if I use corrected bash syntax I get basic compatibility with the Solaris test (regardless of whether the curly brace is on the same line as the parens):

Code:
$ cat MyFun
#! /bin/ksh
print -- "In file MyFun, before def of function MyFun. PID=$$, system=$( uname -rsv )"
MyFun() {
print -- "In function MyFun. PID=$$, system=$( uname -rsv )"
return $(( $# % 128 )) #number of arguments mod 128
}
print -- "In file MyFun, after def of function MyFun. PID=$$, system=$( uname -rsv )"

Running the above in Linux:
Code:
$ . MyFun
In file MyFun, before def of function MyFun. PID=37604, system=Linux 2.6.32-220.el6.x86_64 #1 SMP Wed Nov 9 08:03:13 EST 2011
In file MyFun, after def of function MyFun. PID=37604, system=Linux 2.6.32-220.el6.x86_64 #1 SMP Wed Nov 9 08:03:13 EST 2011
$ MyFun
In function MyFun. PID=37604, system=Linux 2.6.32-220.el6.x86_64 #1 SMP Wed Nov 9 08:03:13 EST 2011
$ . MyFun
In file MyFun, before def of function MyFun. PID=37604, system=Linux 2.6.32-220.el6.x86_64 #1 SMP Wed Nov 9 08:03:13 EST 2011
In file MyFun, after def of function MyFun. PID=37604, system=Linux 2.6.32-220.el6.x86_64 #1 SMP Wed Nov 9 08:03:13 EST 2011

The above still isn't acceptable because using the bash sytax, the function's name is not stored in $0 inside the function body when it executes.

Last edited by charles_n_may; 02-06-2014 at 06:16 PM..
# 4  
Old 02-06-2014
Are you sure your Linux' /bin/ksh is really a ksh and not a link to somewhere else?
# 5  
Old 02-06-2014
For my linux host:

Code:
 
$ which ksh
/bin/ksh

$ print ${.sh.version}
Version JM 93t+ 2010-06-21

# 6  
Old 02-06-2014
ksh supports two types of function definition syntax:
Code:
 name() {body;}

result in a Posix style function. No scoping allowed and thus side-effects abound.
Code:
function name {body;}

Standard ksh functions. You can define local variables and have local signals.

With newer version ksh (such as inhabit linux) the . command has been expanded. In addition to sourcing a filename, the argument to the . command can now be a function. This invokes the function forcing it into local scope. This new feature is killing you. One idea is to name the file and the function it contains differently. . MyFunc.def would define a function called MyFunc. Then you have no name collision. Another idea is to use a pathname:. ./MyFunc.

The behavior you describe on AIX is strange. I can't explain that. But I think I could induce it. Try this:
Code:
if [[ $MyFunDef != "true" ]] ; then
        export MyFunDef="true"
        #! /bin/ksh  this line serves no purpose in a sourced file
        print -- "In file MyFun, before def of function MyFun. PID=$$, system=$( uname -rsv )"
        function MyFun
        {
        print -- "In function MyFun. PID=$$, system=$( uname -rsv )"
        return $(( $# % 128 )) #number of arguments mod 128
        }
        print -- "In file MyFun, after def of function MyFun. PID=$$, system=$( uname -rsv )"
fi


Last edited by Perderabo; 02-06-2014 at 06:37 PM..
These 3 Users Gave Thanks to Perderabo For This Post:
# 7  
Old 02-06-2014
Well now this is promising. I will look into that in more detail overnight. Simply using the dot - dot-slash notation also makes the linux version at least compatible with Solaris. I modified the function slightly to show the value of $0 inside it here:

Code:
 
$ cat MyFun
#! /bin/ksh
print -- "In file MyFun, before def of function MyFun. PID=$$, system=$( uname -rsv )"
function MyFun {
  print -- "In function MyFun. \$0=$0. PID=$$, system=$( uname -rsv )"
  return $(( $# % 128 )) #number of arguments mod 128
}
print -- "In file MyFun, after def of function MyFun. PID=$$, system=$( uname -rsv )"

Running in linux:

Code:
$ . ./MyFun
In file MyFun, before def of function MyFun. PID=19620, system=Linux 2.6.32-220.el6.x86_64 #1 SMP Wed Nov 9 08:03:13 EST 2011
In file MyFun, after def of function MyFun. PID=19620, system=Linux 2.6.32-220.el6.x86_64 #1 SMP Wed Nov 9 08:03:13 EST 2011
$ MyFun
In function MyFun. $0=MyFun. PID=19620, system=Linux 2.6.32-220.el6.x86_64 #1 SMP Wed Nov 9 08:03:13 EST 2011
$ . ./MyFun
In file MyFun, before def of function MyFun. PID=19620, system=Linux 2.6.32-220.el6.x86_64 #1 SMP Wed Nov 9 08:03:13 EST 2011
In file MyFun, after def of function MyFun. PID=19620, system=Linux 2.6.32-220.el6.x86_64 #1 SMP Wed Nov 9 08:03:13 EST 2011



Login or Register to Ask a Question

Previous Thread | Next Thread

10 More Discussions You Might Find Interesting

1. Shell Programming and Scripting

ksh / AIX - Differences between lists to a text file

This seems pretty simple, but I cant figure it out. I get stumped on the simple things. I am running two commands 1) take a listing a directory of files, and filter out the doc_name (which is in a series of extracted files), and place it in a file. ls -l | awk '{print $9}' | grep... (5 Replies)
Discussion started by: jeffs42885
5 Replies

2. Shell Programming and Scripting

Sourcing Env file with eval works with ksh but not BASH

Hi, I am running this on Redhat 5.10 I have a simple test script called test.sh which has the following contents and it uses the BASH shebang. ------------------------------------------------------------- #!/bin/bash eval `/tmp/filereader.pl /tmp/envfile.txt` echo "TESTPATH=$TESTPATH" ... (28 Replies)
Discussion started by: waavman
28 Replies

3. Shell Programming and Scripting

Manipulating field differences using ksh

I have a list of files that should contain the following Im trying to find the items of interest that are missing from each file and create a csv. cat *.txt | while read file do grep 3500 file | tr '\012' ',' done My problem is this possible output one.txt ... (2 Replies)
Discussion started by: popeye
2 Replies

4. Shell Programming and Scripting

ksh script migration from Solaris to Linux.

We are migrating some scripts (ksh) from Solaris 10 to Linux 2.6.32. Can someone share list of changes i need to take care for this ? Have found few of them but i am looking for a exhaustive list. Thanks. (6 Replies)
Discussion started by: Shivdatta
6 Replies

5. AIX

Aix process CPU differences.

Hi, I'm trying to create a script to catch a process which is consuming high CPU which I have pretty much done but it's just finding the correct place to pull the current CPU for that process. When viewed in Topas it's consuming 99.*% cpu But if I try using ps avg or ps -eo pcpu ... (5 Replies)
Discussion started by: elmesy
5 Replies

6. Solaris

rootsh on Solaris 10 is not sourcing root's .profile

I'm attempting to setup rootsh on Solaris 10 to log the activity of users who require root access. However it does not appear to be sourcing root's .profile file even when run with the '-i' option. I was wondering if anybody else has run into this and might have a solution. Thank you. (9 Replies)
Discussion started by: kungfusnwbrdr
9 Replies

7. UNIX for Dummies Questions & Answers

Guide to differences between Solaris and AIX

I've been more used to Solaris, but am now working on an IBM AIX box, P650 Certain commands like "top" are no longer available. Any ideas on where I can find help on this matter? Christopher Freville Alberquerque, NM (6 Replies)
Discussion started by: Solariums
6 Replies

8. UNIX for Dummies Questions & Answers

script sourcing problem (ksh)

I have a script "abc.sh" in /tmp which has exit 0 as its last line when I run this script from /tmp/xyz/def.sh script as . ../abc.sh then the script executes but the control doesn't return to def.sh script for subsequent commands in def.sh but if I invoke the abc.sh from inside the... (3 Replies)
Discussion started by: rakeshou
3 Replies

9. UNIX for Dummies Questions & Answers

Major differences between AIX, Solaris, HP-UX, Linux

Hi All, I want to know the OS level differences between AIX, Solaris, HP-UX, Linux Apart from the vendor, H/w and command differences, any other significant points. regards, guru Charan (9 Replies)
Discussion started by: gurukottur
9 Replies

10. BSD

OpenBSD sh and ksh differences?

Hi, I am running OpenBSD 3.7, my first attempt with this OS. I noticed that both /bin/sh and /bin/ksh are both really the pdksh. Yet each has its own manpage. I was wondering what are the differences b/w the two programs on OpenBSD. I.e., has the team configured pdksh to function one way if... (3 Replies)
Discussion started by: hadarot
3 Replies
Login or Register to Ask a Question