问题
I'm trying to write some code in bash which uses introspection to select the appropriate function to call.
Determining the candidates requires knowing which functions are defined. It's easy to list defined variables in bash using only parameter expansion:
$ prefix_foo="one"
$ prefix_bar="two"
$ echo "${!prefix_*}"
prefix_bar prefix_foo
However, doing this for functions appears to require filtering the output of set -- a much more haphazard approach.
Is there a Right Way?
回答1:
How about compgen:
compgen -A function # compgen is a shell builtin
回答2:
$ declare -F
declare -f ::
declare -f _get_longopts
declare -f _longopts_func
declare -f _onexit
...
So, Jed Daniel's alias,
declare -F | cut -d" " -f3
cuts on a space and echos the 3rd field:
$ declare -F | cut -d" " -f3
::
_get_longopts
_longopts_func
_onexit
回答3:
I have an entry in my .bashrc
that says:
alias list='declare -F |cut -d" " -f3'
Which allows me to type list
and get a list of functions. When I added it, I probably understood what was happening, but I can't remember to save my life at the moment.
Good luck,
--jed
回答4:
This has no issues with IFS nor globbing:
readarray -t funcs < <(declare -F)
printf '%s\n' "${funcs[@]##* }"
Of course, that needs bash 4.0.
For bash since 2.04 use (a little trickier but equivalent):
IFS=$'\n' read -d '' -a funcs < <(declare -F)
If you need that the exit code of this option is zero, use this:
IFS=$'\n' read -d '' -a funcs < <( declare -F && printf '\0' )
It will exit unsuccesful (not 0) if either declare
or read
fail. (Thanks to @CharlesDuffy)
回答5:
One (ugly) approach is to grep through the output of set:
set \
| egrep '^[^[:space:]]+ [(][)][[:space:]]*$' \
| sed -r -e 's/ [(][)][[:space:]]*$//'
Better approaches would be welcome.
回答6:
Use the declare builtin to list currently defined functions:
declare -F
回答7:
Pure Bash:
saveIFS="$IFS"
IFS=$'\n'
funcs=($(declare -F)) # create an array
IFS="$saveIFS"
funcs=(${funcs[@]##* }) # keep only what's after the last space
Then, run at the Bash prompt as an example displaying bash-completion functions:
$ for i in ${funcs[@]}; do echo "$i"; done
__ack_filedir
__gvfs_multiple_uris
_a2dismod
. . .
$ echo ${funcs[42]}
_command
回答8:
Perhaps my solution for this thread will work for you. Google for "get a list of function names in a shell script site:stackoverflow.com"
get a list of function names in a shell script
回答9:
This collects a list of function names matching any of a list of patterns:
functions=$(for c in $patterns; do compgen -A function | grep "^$c\$")
The grep limits the output to only exact matches for the patterns.
Check out the bash command type as a better alternative to the following. Thanks to Charles Duffy for the clue.
The following uses that to answer the title question for humans rather than shell scripts: it adds a list of function names matching the given patterns, to the regular which
list of shell scripts, to answer, "What code runs when I type a command?"
which() {
for c in "$@"; do
compgen -A function |grep "^$c\$" | while read line; do
echo "shell function $line" 1>&2
done
/usr/bin/which "$c"
done
}
So,
(xkcd)Sandy$ which deactivate
shell function deactivate
(xkcd)Sandy$ which ls
/bin/ls
(xkcd)Sandy$ which .\*run_hook
shell function virtualenvwrapper_run_hook
This is arguably a violation of the Unix "do one thing" philosophy, but I've more than once been desperate because which
wasn't finding a command that some package was supposed to contain, me forgetting about shell functions, so I've put this in my .profile.
回答10:
#!/bin/bash
# list-defined-functions.sh
# Lists functions defined in this script.
#
# Using `compgen -A function`,
# We can save the list of functions defined before running out script,
# the compare that to a new list at the end,
# resulting in the list of newly added functions.
#
# Usage:
# bash list-defined-functions.sh # Run in new shell with no predefined functions
# list-defined-functions.sh # Run in current shell with plenty of predefined functions
#
# Example predefined function
foo() { echo 'y'; }
# Retain original function list
# If this script is run a second time, keep the list from last time
[[ $original_function_list ]] || original_function_list=$(compgen -A function)
# Create some new functions...
myfunc() { echo "myfunc is the best func"; }
function another_func() { echo "another_func is better"; }
function superfunction { echo "hey another way to define functions"; }
# ...
# function goo() { echo ok; }
[[ $new_function_list ]] || new_function_list=$(comm -13 \
<(echo $original_function_list) \
<(compgen -A function))
echo "Original functions were:"
echo "$original_function_list"
echo
echo "New Functions defined in this script:"
echo "$new_function_list"
来源:https://stackoverflow.com/questions/2625783/listing-defined-functions-in-bash