Re: how to make function known to subshell

From: Hans Horn (hannes_at_2horns.com)
Date: 11/18/04


Date: Thu, 18 Nov 2004 08:22:12 GMT

Thanks everybody!

This is what I tried:

In my .profile I source a file with a my shell functions, e.g.
  . .shell_functions

and set ENV to a file that autoloads them
  export ENV=$HOME/.functions_autoload

file .functions_autoload contains e.g.
  echo "autoloading"
  autoload function1
  autoload function2
  ...

When I open a new ksh shell or execute a shell script, the text
"autoloading" is displayed.

If the shell script however invokes, say function1, the function does NOT
get executed, I do not even get a complaint!
I have to explicitly specify "autoload function1" in the shell script to
make it work.

Is this was is supposed to happen - and am I just not getting it?

Or am I doing something wrong here?

greets,
H.

Dan Mercer wrote:
> "Hans Horn" wrote in message
> news:uwdmd.13000$zx1.707@newssvr13.news.prodigy.com...
>> Group,
>>
>> suppose I define a function x() in my .profile.
>>
>> I thought x() would be automatically available in shell scripts and
>> subshells.
>> But this is not the case (I'm using ksh).
>>
>> What do I have to do to make a function available in shell scripts or
>> subshells?
>>
>> thx,
>> H.
>>
>> 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
> a list of paths where executable files may be found, FPATH is a
> list of paths where readable files containing function definitions
> may be found. The names of the readable files in the FPATH
> hierarchy are stored by the ksh as "undefined functions" (whether
> they contain function definitions or not).
>
> When a command is searched for, pathed names (those with a "/"
> in them) are found first. If the name is not pathed, the list
> of builtins is searched, then the list of known functions, then
> the PATH is searched for a file with a matching name and finally
> the FPATH is searched for a file with a matching name. All
> defined functions are "known". You can make an undefined
> function "known" by autoloading it with the "autoload" alias.
> This will give the undefined function higher precedence than
> PATH'd commands.
>
> When an undefined function is used (not when it's autoloaded) the file
> will be sourced, then the function called. The function file
> therefore must contain a function definition, for instance:
>
> $ cat /usr/common/fun/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
> }
>
> The file can contain additional commands including multiple function
> definitions that will all be defined simultaneously.
>
> =======================================================================
> $ cat ~/fun/set_cdpath
> ((DEBUG)) && print "sourcing set_cdpath..."
> function set_cdpath
> {
> typeset _path
> if (($#))
> then
> [[ $1 = . ]] && set -- $PWD
> set -A _path "$@" "$CDPATH"
> else
> set -A _path . \
> ~ \
> ~/devel/src/applix \
> ~/devel/src \
> ~/devel \
> ~/axhome \
> ~asterx \
> ~/.dt \
> /usr/local
> fi
> typeset IFS=:
> CDPATH=${_path[*]}
> unset -f set_cdpath
> }
>
> If $DEBUG is non-zero, when the file is initially sourced you will
> see a message.
>
> You can also include multiple function definitions in the same file.
> All will be defined when the function matching the file name is
> sourced.
> For instance, you could have a dtksh function to use the DtComboBox
> called "DtComboBoxInitialize" which would install all the functions
> required
> to use the combo box.
>
> Once a file has been sourced, the function is now defined, and moves
> ahead of the PATH search in the execution hierarchy. You may undefine
> it using the "unset -f funcname" command as I have done in the example
> above.
>
> Functions operate in the current environment, so an exit will exit
> the shell. You need to use "return" to exit a function.
>
> Functions can be used in subshells or in command substitutions, but
> in those cases they will not modify the current environment.
>
>
> EXAMPLES
> ========
>
> Setting the path:
>
> function set_path
> {
> typeset IFS=":$IFS" _p
> if (($#))
> then
> set -A _p ${PATH%:.}
> for dir
> do
> [[ $dir = . ]] && dir=$(/usr/bin/pwd)
> if [[ -d $dir ]]
> then
> [[ $PATH = ?(*:)$dir?(:*) ]] || {
> _p[${#_p[*]}]="$dir"
> }
> else
> echo "Directory $dir not found - not added to PATH"
> fi
> done
> PATH="${_p[*]}:."
> else
> unset PATH
> set_path ~/bin*(2) \
> /usr/*(s)bin \
> /usr/dt/bin \
> /usr/bin/X11 \
> /usr/+(contrib|dt|local)/bin \
> /usr/+(contrib|local)/bin/X11 \
> /usr/X11R6.3/bin \
>
> /opt/+(CC|allbase|ansic|dtscript3.0|hpnp|image|langtools|gv|rcs)/bin
> fi
> export PATH
>
> unset -f set_path
> }



Relevant Pages

  • Re: Automating alias saving in bash
    ... >Well, I install a lot of short lived systems for testing, and I noticed ... >with aliases, and maybe use them later too, or then not. ... variables and shell functions are. ... commands, so don't waste them on things you don't do repeatedly, ...
    (comp.os.linux.misc)
  • Re: Redirection issue
    ... 1- execute input commands from standard input, ... code to implement the redirection it does not work anymore. ... And it's not good shell behavior to echo commands anyway. ...
    (comp.lang.c)
  • Re: Redirection issue
    ... 1- execute input commands from standard input, ... the phrase "it does not work anymore" carries very little meaning. ... after compilation and execution of the shell with a simple command like ...
    (comp.lang.c)
  • vulnerabilities in scponly
    ... without allowing shell access. ... scponly makes no effort to verify the path to the scp or sftp-server ... arbitrary commands by simply uploading a file. ... However, if this is *NOT* the case, the user could execute arbitrary ...
    (Bugtraq)
  • Re: Redirection issue
    ... 1- execute input commands from standard input, ... "does not work" could be anything from not compiling, not executing, ... after compilation and execution of the shell with a simple command like ...
    (comp.lang.c)