我正在尝试使用内省来选择要调用的适当函数。
确定候选函数需要知道哪些函数已定义。在bash中,只使用参数扩展就可以轻松列出已定义的变量:
$ prefix_foo="one"
$ prefix_bar="two"
$ echo "${!prefix_*}"
prefix_bar prefix_foo
然而,对于函数来说,这似乎需要过滤set的输出——这是一种更加杂乱无章的方法。
有没有正确的方法?
我正在尝试使用内省来选择要调用的适当函数。
确定候选函数需要知道哪些函数已定义。在bash中,只使用参数扩展就可以轻松列出已定义的变量:
$ prefix_foo="one"
$ prefix_bar="two"
$ echo "${!prefix_*}"
prefix_bar prefix_foo
然而,对于函数来说,这似乎需要过滤set的输出——这是一种更加杂乱无章的方法。
有没有正确的方法?
那么关于 compgen 呢:
compgen -A function # compgen is a shell builtin
compgen -A function prefix_
) - Charles Duffy$ declare -F
declare -f ::
declare -f _get_longopts
declare -f _longopts_func
declare -f _onexit
...
所以,Jed Daniel的别名,
declare -F | cut -d" " -f3
根据空格分割并输出第三个字段:
$ declare -F | cut -d" " -f3
::
_get_longopts
_longopts_func
_onexit
我在我的.bashrc
文件中有一个条目,内容如下:
alias list='declare -F |cut -d" " -f3'
这使我可以输入list
并获得一个函数列表。当我添加它时,我可能知道发生了什么,但是现在我无论如何都记不起来了。
祝你好运,
--jed
declare -F
${!prefix_*}
,而在命令行中添加cut
并不像坚持使用内置命令那样干净。 - Charles Duffyzsh
仅支持(不是要求的内容,但所有更通用的问题都被视为此问题的重复):
typeset -f +
来自man zshbuiltins
:
-f The names refer to functions rather than parameters.
+ If `+' appears by itself in a separate word as the last
option, then the names of all parameters (functions with -f)
are printed, but the values (function bodies) are not.
示例:
martin@martin ~ % cat test.zsh
#!/bin/zsh
foobar()
{
echo foobar
}
barfoo()
{
echo barfoo
}
typeset -f +
输出:
martin@martin ~ % ./test.zsh
barfoo
foobar
这个没有与IFS或globbing相关的问题:
readarray -t funcs < <(declare -F)
printf '%s\n' "${funcs[@]##* }"
IFS=$'\n' read -d '' -a funcs < <(declare -F)
IFS=$'\n' read -d '' -a funcs < <( declare -F && printf '\0' )
如果declare
或read
失败,它将以非0的退出方式结束。感谢@CharlesDuffy。
declare -f
读入数组中,并在扩展时将它们剥离出来。在2.0.4版本的情况下,可能会使其变为declare -F && printf '\0'
— 这样,read
将具有零的退出状态(并且,作为额外的奖励,任何阻止declare -F
工作的错误都会有效地传递)。 - Charles Duffy一种(丑陋的)方法是通过set的输出进行grep:
set \
| egrep '^[^[:space:]]+ [(][)][[:space:]]*$' \
| sed -r -e 's/ [(][)][[:space:]]*$//'
欢迎提出更好的方法。
纯Bash:
saveIFS="$IFS"
IFS=$'\n'
funcs=($(declare -F)) # create an array
IFS="$saveIFS"
funcs=(${funcs[@]##* }) # keep only what's after the last space
然后,在Bash提示符下运行,例如显示bash-completion函数:
$ for i in ${funcs[@]}; do echo "$i"; done
__ack_filedir
__gvfs_multiple_uris
_a2dismod
. . .
$ echo ${funcs[42]}
_command
funcs =($(IFS = $'\ n'; funcs =($(declare -F)); echo“$ {funcs [@] ## *}”))
),这显然更加功能强大(而不是美观)丑陋。 - Charles Duffyfunctions=$(for c in $patterns; do compgen -A function | grep "^$c\$")
grep限制输出仅匹配模式的精确结果。
查看bash命令type作为以下更好的替代方案。感谢Charles Duffy提供线索。
以下使用它来回答标题问题,而不是shell脚本:它添加了与给定模式匹配的函数名称列表到shell脚本的常规which
列表中,以回答“当我键入一个命令时,哪些代码运行?”
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
}
(xkcd)Sandy$ which deactivate
shell function deactivate
(xkcd)Sandy$ which ls
/bin/ls
(xkcd)Sandy$ which .\*run_hook
shell function virtualenvwrapper_run_hook
which
无法找到某个包应该包含的命令而感到绝望,而忘记了shell函数,所以我把它放在了我的.profile文件中。which
来列出已定义的函数,而是将已定义的函数列表添加到which
中。我已经编辑了帖子来说明原因。 - FutureNerdtype
的默认操作有何不同?(此外,type
处理内置函数、shell语法等内容,而此命令则不包括在内)。 - Charles Duffy#!/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"
<(compgen -A function)
会更有效率。也可以将grep的工作放到awk行中:awk '/>/ {print $2}'
,从而消除冗余。实际上,最好完全放弃diff;当你只想进行设置比较时,它比comm大大不如。 - Charles Duffyfoo='*'; echo $foo
与foo='*'; echo "$foo"
进行比较。 - Charles Duffy[[ $original_function_list ]] || original_function_list=$(...)
- Charles Duffy