Unable to run function

Hi,

I have a separate file with a ksh function in it. When I try to run it, I get an error about permissions:

user@~/scripts/functions$ ksh f_fill_testfunc
ksh: f_fill_testfunc: cannot open [Operation not permitted]
user@~/scripts/functions$ ls -l batch_functions/f_fill_testfunc
-rwxr-xr-x 1 user user 1105 Aug 29 16:12 batch_functions/f_fill_testfunc
user@~/scripts/functions$ cat batch_functions/f_fill_testfunc
function f_fill_testfunc
{
        # Just some stuff
}

The directory is present in $FPATH, so i don't see the problem. Does anyone know why I can't run it?

EDIT:

I just tried to run it from within a script, and that works fine for some reason. Is there no way to run a ksh function without the use of a script?
I'm running Red Hat 5.2 by the way.

user@~/scripts/functions$ cat test.ksh
#!/bin/ksh

f_fill_testfunc

We cant help you if you dont show us what your function is doing ( to generate such error...)

I can't run any of the functions, so I don't think it has anything to do with the script itself.
I just changed it to this, and it still gives the same error:

function f_fill_testfunc
{
    echo test
}

reminds me of (extended) file attributes. Could you post the result of lsattr f_fill_testfunc?

This is the output:

$ lsattr f_fill_testfunc
------------- f_fill_testfunc

too bad! What about the permissons of the batch_functions directory itself? And - can you try to source the script (like . f_fill_testfunc)?

I can source it, and it's loaded in the FPATH. The directory seems ok as well:

user$ ls -l | grep batch_functions
drwxr-xr-x 2 user user 1024 Aug 30 10:53 batch_functions

No clue what it is still :wall:

if you want to use the functions in your another script please use below code in your script..

source /PATH/Function_script_name

#For using function give function name

and if you want to use the functions in bash just use..

. /PATH/Function_script_name

#For using function give function name

It should work just by adding the directory in which the function is to your $FPATH variable. It works in my other environment (Solaris)... And I can just run the function from within a script without having to source it, just not from the command line.

The FPATH variable works in ksh (and only ksh - bash doesn't have it!) provided that:

1.) The files where the functions reside in are mode 4 or 6 to the UID of the calling script. I flag them 644 and give ownership to root:system (on AIX - Linux would be "root:root") usually. They should NOT have the x-bit set! This is important.

2.) Every function should reside in its own file (do NOT bundle functions into files) and the file should be named like the fuction itself. The first executable line in the file should be the function definition:

$ echo $FPATH
/path/foo:/path/bar

$ ls -l /path/foo/f_foobar
total 112
-rw-r--r--    1 root     system         154 Aug 30 12:04 f_foobar

$ cat /path/foo/f_foobar
# some comment about f_foobar()

f_foobar ()
{
   <here goes your code>
   return 0
}
# EOF f_foobar

3.) You have to be aware, that FUNCTIONS ARE NOT SCRIPTS! You can't just execute them on their own. You have to call them from within your scripts:

#! /bin/ksh

FPATH=/path/foo:/path/bar ; export FPATH

f_foobar arg1 arg2 arg3 ...

exit 0

I work with a collection of these functions since years and maintain my handy little library with all sorts of solutions for day-to-day-scripting.

I hope this helps.

bakunin

And directories in FPATH should be in PATH .

Thanks for the comment Bakunin.

As I said, I can run the functions from within a script without a problem provided that I set the FPATH with the correct directory.

However, I can't run the function from the command line using 'ksh functionname', even though I have the same setup on another system running solaris instead of red hat which works fine :frowning:

When you test your functions, do you always create a separate script to call that function?

Have you tried to run with only 'functionname'??

Hmm I feel kinda stupid for not trying that before. But when I switch to a ksh shell (instead of default bash) and I run just the function name, it works.
I don't understand why is doesn't work when I run it from within the bash shell using 'ksh functionname'

Yes, i do that. It is called "regression test" because functions in my library usually do some pretty abstracted things and i want them to be as reliable as possible. If you search the forums for my name and "ksh function" you will even find some examples of what i wrote.

My usual setup is like this:

i have my library in "/usr/local/lib/ksh" and all my function names start with "f_". This way i know immediately which are external functions and which are not in complex scripts.

I have one "environment" function, which i source in at the beginning of every script and which sets the environment from the beginning, including PATH, FPATH and so on. This way i have always the same environment in every script i write and don't have to worry about scripts being started from crontab and similar common problems.

In addition i have one environment variable "DEVELOP", which is tested in the environment function. If it has any value at all FPATH is not set to "/usr/local/lib/ksh" but to "~/lib", so that a local copy of the library in my $HOME is used. This way i can locally test the scripts with new versions of the lib functions (my user has this variable set in ".kshrc") and then just roll out the scripts. Other users don't have the variable set so they will automatically use the general version of the library with no change.

usual script start:

#! /bin/ksh

if [ -n "$DEVELOP" ] ; then
     . ~/lib/f_env
else
     . /usr/local/lib/ksh/f_env
fi

# set local vars after this, f_env clears the environment first
typeset localvar=....

... rest of code
exit 0

f_env would look like this (parts):

f_env ()
{
if [ -z "$NEVER_USE_THIS_VAR" ] ; then           # are we called recursively ?

     unset ENV                                   # clear the environment

     #---------------------------------------------------- set basic environment
     typeset -x OS=$(uname -a | cut -d' ' -f1)   # find out the OS
                                                 # read in standard environment
     case "$OS" in
          AIX)
               . /etc/environment
               ;;

          Linux)
               . /etc/profile
               ;;

          *)
               . /etc/environment
               ;;
     esac
                                                 # set default TERM variable
     case "$OS" in
          AIX)
               TERMDEF="$(termdef)"
               ;;

          Linux)
               TERMDEF="$TERM"
               ;;

          *)
               TERMDEF="$TERM"
               ;;

     esac
     typeset -x TERM=${TERMDEF:-'wyse60'}        # set default TERM variable

     typeset -x LANG=C                           # default language environment
     typeset -x EDITOR=vi                        # what else ? ;-))
     typeset -x VISUAL=$EDITOR

     typeset -x PATH="/usr/bin"                  # set the path
                PATH="$PATH:/bin"
                PATH="$PATH:/etc"
                PATH="$PATH:/usr/sbin"
                PATH="$PATH:/usr/ucb"
                PATH="$PATH:/sbin"
                PATH="$PATH:/usr/bin/X11"
                PATH="$PATH:/usr/local/bin"      # tools, home for scripts
                PATH="$PATH:/usr/local/sbin"     # -"-

     typeset -x chTmpDir=""                      # path for temporary files

     #---------------------------------------------------- debugging stuff
     if [ -z "$chFullDebug" ] ; then             # debug switch
          typeset -x chFullDebug=""
     else
          typeset -x chFullDebug                 # export if already set
     fi
     typeset -x SIMULATE=''                      # set to 'print' for
                                                 # simulation mode
     typeset -x TRACE=''                         # set to 'on' for trace mode

     if [ -z "$DEVELOP" ] ; then
          typeset -x FPATH="/usr/local/lib/ksh"  # set fnc path for fnc lib
          FPATH="$FPATH:/usr/local/bin"
          FPATH="$FPATH:/usr/local/sbin"
     else
          typeset -x FPATH=~/lib        # for lib development
     fi
     #---------------------------------------------------- global constants
     typeset -x chProgName="$0"                  # const. for main program name

     typeset -x chUsageShort=""                  # short usage message
     typeset -x achUsageLong[0]=""               # long usage message (line)

     if [ -z "$fLogFile" ] ; then                # log file
          if [ $(f_ImRoot ; print $?) -eq 0 ] ; then
               typeset -x fLogFile='/usr/local/log/swd.log'
          else
               typeset -x fLogFile=~/swd.log
          fi
     else
          typeset -x fLogFile
     fi
     if [ -z "$fErrFile" ] ; then                # error file
          if [ $(f_ImRoot ; print $?) -eq 0 ] ; then
               typeset -x fErrFile='/usr/local/log/swd.err'
          else
               typeset -x fErrFile=~/swd.err
          fi
     else
          typeset -x fErrFile
     fi

     .... etc. ....
     #-------------------------------------------------- reentrancy protection
     typeset -x NEVER_USE_THIS_VAR="KILROY_WAS_HERE"
fi
}

There are also parts dealing with supported alerting systems (BMC Patrol, HP OpenView, and some other are supported), and some site-dependent stuff, but i think you get the drift.

Notice the "if [ -z "$DEVELOP" ]" line, where the FPATH is set accordingly.

I hope this helps.

bakunin

2 Likes

Thanks bakunin, very useful post!

Have a close look at what is inside the function file: there is only the function definition, not a call to it!

if you enter the following into ksh (or bash, doesn't matter):

foobar ()
{
     echo "hello world."
}

what will happen? Nothing! YOu have defined what the shell should understand when you issue "foobar" at the command line, but not issued it! Now try the following (with a new shell):

foobar ()
{
     echo "hello world."
}
foobar

It will now print "hello world.", because you ahve first defined the function (line 1-4) and then called it (line 5).

I hope this helps.

bakunin

I understand, but I call the function, not the file.
As long as the file in which the function is is in $FPATH, and I call it from another directory so I don't run the script instead using 'ksh functionname', it should work. It works this way on my other system running Solaris:

user$:~/scripts/functions$ cat f_testfunction
f_testfunction() {
        echo test
}
user$:~/scripts/functions$ cd ..
user$:~/scripts$ ksh f_testfunction
test

Agreed. Maybe the FPATH isn't set to what you think it is. After all, issuing ksh functionname invokes another shell, which has its own environment. You might try, for debugging purposes, to do

ksh print - "$FPATH" ; functionname

and see what happens.

I hope this helps.

bakunin