unix shell functions and capturing their return values...

unix shell functions and capturing their return values...

Post by Aidan O'Haga » Tue, 26 Sep 2000 04:00:00



Folks,

Is there a way to call a function in unix shell scripts and return a value
back into a variable other than the way it's done below.....
This version seems to create another process for each call to a function.
Any help would be excellent.

Cheers
Aidan

#!/bin/sh
fun4 () {
 echo tt

Quote:}

test=`fun4`
echo $test

--
l

 
 
 

unix shell functions and capturing their return values...

Post by David Hasset » Tue, 26 Sep 2000 04:00:00



> Is there a way to call a function in unix shell scripts and return a value
> back into a variable other than the way it's done below.....

Yes, set the variable inside the function. Unless you declare it
'local', the value will remain once the function has executed. e.g.

#!/bin/sh
fun4 () {
 test=tt

Quote:}

fun4
echo $test

Produces:

tt

Quote:> This version seems to create another process for each call to a function.

That's because you executed the function from inside a command
substitution. This wil always spawn another process. If you are using an
up-to-date shell, I would re-write your version of the script as:

#!/bin/sh
fun4 () {
 echo tt

Quote:}

test=$(fun4)
echo $test

Bracket command substitution is _much_ easier to nest, and so is always
preferable over backticks. You have to work with an older shell, so this
is not always good advice. The above version still spawns another
process however. :-)

Cheers,

Dave. :-)

 
 
 

unix shell functions and capturing their return values...

Post by Dan Merc » Tue, 26 Sep 2000 04:00:00


In article <8qndme$5f...@pheidippides.axion.bt.co.uk>,

"Aidan O'Hagan" <m...@nospamers.btinternet.com> writes:
> Folks,

> Is there a way to call a function in unix shell scripts and return a value
> back into a variable other than the way it's done below.....
> This version seems to create another process for each call to a function.
> Any help would be excellent.

> Cheers
> Aidan

> #!/bin/sh
> fun4 () {
>  echo tt
> }

> test=`fun4`
> echo $test

> --
> l

functions modify the current environment.  You don't have to return
anything.  For instance:

    fun4() {
    test=tt
    }

    fun4
    echo $test

produces:

    tt

Maybe you don't want to hardcode the env var - in which case,  pass it:

    fun4() {
    eval ${1:?Argument required}=tt
    }

    fun4 test
    echo $test

produces:

    tt

Here's my function tutorial.  It is geared towards the ksh.  The
Bourne shell is obsolescent and is likely to be the default shell only on
very old systems,  whereas some form of ksh should be universally
available.

__
Dan Mercer
damer...@uswest.net

                     FUN WITH FUNCTIONS (and aliases)
                     ================================

Shell scripts,  with all their power,  have one major drawback - they
do not modify the current shell's environment.  To do that,  one
must resort to aliases and functions.

ALIASES
=======

An alias just performs a textual replacement of one string for another,
for instance:

      $ alias foo=bar
      $ foo
      ksh: bar:  not found

When a command is parsed the first word will be checked against the
defined aliases.  If an exact match is found,  the word is replaced
by the defined text.  If the word does not match exactly,  it is not
replaced.  Look what happens if I continue the example above using the
strings \foo, 'foo', "foo".

      $ \foo
      ksh: foo:  not found
      $ 'foo'
      ksh: foo:  not found
      $ "foo"
      ksh: foo:  not found

Note that no aliasing occurred.

Since the text substitution occurs before the line is parsed,  you
cannot pass parameters to ksh aliases like you can csh.  Csh aliases
are a weaker version of ksh functions.  If you want to pass parameters
you must use functions.

Aliases can be used to track frequently called programs,  so that
you don't have to traverse the PATH variable everytime you call the
command.  Ksh comes with builtin tracked aliases that can be listed
with the "alias" command after they have been accessed:

      $ alias -t -
      cat=/usr/bin/cat

The alias "hash" is an alias for "alias -t -".  If you say:

      $ alias -t xterm

then the shell will examine the current value of the PATH and if
it finds an executable named xterm it will alias the full path
to the word "xterm":

      $ hash
      cat=/usr/bin/cat
      xterm=/usr/bin/X11/xterm

If the PATH is reset,  the next time an aliased command is run the
alias will be recomputed.  If you run "whence" on the command (and
remember,  "type" is an alias for "whence -v",  the alias will be
recomputed.  For instance,  continuuing the example:

      $ for i in /usr/bin/*;do type ${i##*/} >/dev/null 2>&1;done

That runs "whence -v" on the basename of every executable in /usr/bin.
Now when I run hash:

      $ hash
      cat=/usr/bin/cat
      cc=/usr/bin/cc
      chmod=/usr/bin/chmod
      cp=/usr/bin/cp
      date=/usr/bin/date
      ed=/usr/bin/ed
      grep=/usr/bin/grep
      ls=/usr/bin/ls
      mail=/usr/bin/mail
      mv=/usr/bin/mv
      pr=/usr/bin/pr
      sed=/usr/bin/sed
      sh=/usr/bin/sh
      vi=/usr/bin/vi
      who=/usr/bin/who
      xterm=/usr/bin/X11/xterm

You can set all commands to be tracked by turning on the
"trackall" option uisng either:

      set -o trackall

or

      set -h

Another interesting feature of aliases is that if an alias
contains a trailing space,  the subsequent word will be examined
for ordinary (not tracked) alias expansion:

      $ alias ll='ls -l '
      $ alias inc=/usr/include
      $ ll inc
      total 1598
      drwxr-xr-x   2 root       sys           5120 Jul  7  1999 FL
      dr-xr-xr-x   5 bin        bin           1024 Oct 19 11:51 Motif1.2
      lr-xr-xr-t   1 root       sys             18 Apr  1  1997 SC -> /opt/CC/include/
      SC
      drwxr-xr-x   3 bin        bin           2048 Oct 19 12:09 X11
      dr-xr-xr-x   3 bin        bin           1024 Mar 17  1998 X11R6
      -r--r--r--   1 bin        bin            605 May 30  1996 a.exec.h
      ...

This can be very useful in changing directories (see the cd example
below).

In command execution,  builtin commands (like cd) have a higher
precedence than functions, which have a higher precedence over
external commands,  which have a higher precedence over undefined
functions (I'm getting to those).

Aliasing takes place before parsing,  so if you want to redefine a
builtin,  you must use an alias.  In the example below,  "pd" is the
name of a function that changes directories,  keeps a stack of the
last traversed directories,  and changes the terminal title bar to
reflect the current directory.  Since the alias ends in a trailing space,
it also allows directory paths to be set up as aliases:

      alias cd='pd '
      function pd
      {
      RT=${PWD:-$(pwd)}
      dir_history $RT
      \cd "$@"

      typeset t
      t="${HOST}:${PWD:=$(pwd)}"
      case $TERM in
         hp*)        echo "\033&f0k${#t}D${t}\033&f-1k${#t}D${t}\c";;
         +(d|x|v)t*) echo "\033]2;${t}\007\c";;
      esac
      echo $PWD
      }

Note that when cd is finally called,  it is escaped with a backslash
as discussed above.  If it was not,  aliasing would replace the
characters "cd" with "pd ",  and the function would recurse until
the stack limit was hit.  A fuller explanation of the above example
follows the discussiong on Functions.

FUNCTIONS
=========

Of Shells and Subshells:
-----------------------

When the shell goes to execute an external command it first forks
the current shell process giving you an entirely new process that
inherits all the information from the old.  It has a new  process
id,  but the "$$" variable is still set to the process id of the
parent process.  A form of the "exec(2)" function is then called.
The "exec(2)" function checks the permission of the file to make
sure it is executable by the current user.  It then opens the
file and reads the first 32 bytes.  If the magic number for a
binary executable is found, then the binary executable is loaded
and it replaces the current process state.  If the magic number
"#!" (called a "shebang") is encountered,  the rest of the line
is parsed for the explicit path to a file. If that file is not
executable,  you get an error message (at least on HP-UX 10.20).
If it is a binary executable,  that binary is called with the
script file name as either the first or second parameter - any
text on the "#!" line following the path being passed as the
first parameter.  If it is not a binary exec returns an error to
the shell.  What happens after that is up to the shell - ksh88 on
HP-UX 10.20 treats the "#!" line as a comment and reads the file
and executes its commands in the current subshell.  "Csh" will
check the first character of the file - if it is a "#" it will
attempt to read and execute its commands in the current subshell
- if it is not a "#",  the subshell will exec "/bin/sh" and pass
it the file to execute.

When a shell script is called by ksh, what is inherited by the
new process differs based on whether there is a shebang.  If there
is not,  the new subshell inherits all exported variables,  exported
aliases (using "alias -x") and exported functions
(using "typeset -fx").  NOTE - ksh93 does not support exported aliases
or functions.  If there is a shebang,  the subshell execs the new
interpreter and the new interpreter only inherits exported scalar
variables.

Regardless of whether they have a shebang or not,  shell scripts
cannot change the current environment,  neither the current
working directory nor the environment variables.  You can,  however,
script changes to the current environment in one of two ways:

   o - use the special "." to "source" the script - i.e. execute
       its commands in the current shell.
   o - use a psecial kind of script called a "function".

In most ways the above methods will produce identical results,
but I am only going to discuss Korn Shell functions here.

A function is a collection of commands  that run in the current
shell.  Thus, it has access to the current shell's environment
and can change its variables and directory.  A function can
either be defined or undefined.  A defined function has had its
commands parsed and stored by the shell.  An undefined function
exists in an external file whose path is known to the shell.

In the Korn Shell,  there are two separate syntaxes for defining
a script - the POSIX (implicit) syntax and a Korn syntax
using the explicit keyword "function".

POSIX:

      tt() { echo "temporary test function"; }

Korn:

      function tt { echo "temporary test function"; }

In ksh88,  the two syntaxes behave identically.  In ksh93,
the POSIX syntax adopts POSIX behavior,  the Korn maintains
the same behavior as all functions had in ksh88.

In Korn behavior,  $0 of the function is the name of the function.
traps are reset inside the function and you can set traps particular
to the function.  A trap on "exit" trips when the function is
exited.  Variables within a Korn function can be made local to the
function by using the "typeset" command - this is very useful when
making multiple passes on an options list using "getopts" or when
doing data splitting by modifying the IFS variable.

In POSIX behavior,  $0 is the $0 of the calling process.  Traps and
variables are global.  On the whole,  far more powerful processing
is possible with Korn functions than POSIX.

The Korn shell adds another wrinkle to function processing -
the FPATH variable.  FPATH is analagous to PATH,  but instead of
...

read more »

 
 
 

1. return value in shell functions

Hi all,

I'm writing some useful functions, to include in my shell scripts (using
ksh)
I don't know how to let a function return a value. Is there a "clean"
way to do it ? (I do it in a dirty way ;-)

I make it so :

=================================================

# read a value in a config-file of the form NAME=VALUE
#
# GetValue { file to search in } { name to search for } [ default value
]
#
function GetValue
{
   local FILE=$1
   local NAME=$2
   local DEFAULT=$3

   local VALUE=$( grep -i "^${NAME}=" $FILE | cut -f 2 -d= | head -n 1)

   if [ "${VALUE}" = "" ]
   then
        VALUE=$DEFAULT
   fi

   echo ${VALUE}

FONT=$( GetValue ${HOME}/.myfilerc font fixed )
==================================================

the function in this example search the file for a row of the form
Name=Value
and write the first occurence (if there are more than one)

My problem here is that in such a function I cannot write some
message error if something goes wrong.

Thanks

Fabio

2. Pausing a directory listing?

3. returning values from a function in a shell script

4. Mouse Problems With KVM Switches

5. return a value from oracle to unix shell help please

6. cable modem help

7. return value to unix shell from oracle

8. Kernel modules missing symbols

9. how do i capture return values for ncftpget

10. return values from functions are limited in size - true ?

11. How To Get A Return Value From A Function

12. Return value of system function

13. Function return value troubles