Re: how to make function known to subshell
From: Hans Horn (hannes_at_2horns.com)
Date: 11/18/04
- Next message: Stephane CHAZELAS: "Re: Double quotation in bash"
- Previous message: Hans Horn: "Re: issues with http://home.comcast.net/~j.p.h/cus-faq.html#M"
- In reply to: Dan Mercer: "Re: how to make function known to subshell"
- Next in thread: dfrench_at_mtxia.com: "Re: how to make function known to subshell"
- Reply: dfrench_at_mtxia.com: "Re: how to make function known to subshell"
- Reply: Dan Mercer: "Re: how to make function known to subshell"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
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
> }
- Next message: Stephane CHAZELAS: "Re: Double quotation in bash"
- Previous message: Hans Horn: "Re: issues with http://home.comcast.net/~j.p.h/cus-faq.html#M"
- In reply to: Dan Mercer: "Re: how to make function known to subshell"
- Next in thread: dfrench_at_mtxia.com: "Re: how to make function known to subshell"
- Reply: dfrench_at_mtxia.com: "Re: how to make function known to subshell"
- Reply: Dan Mercer: "Re: how to make function known to subshell"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Relevant Pages
|