列出 Bash 中定义的函数

发布于 2024-08-29 03:47:06 字数 292 浏览 2 评论 0原文

我正在尝试在 bash 中编写一些代码,它使用内省来选择要调用的适当函数。

确定候选者需要了解定义了哪些功能。仅使用参数扩展就可以轻松地在 bash 中列出已定义的变量

$ prefix_foo="one"
$ prefix_bar="two"
$ echo "${!prefix_*}"
prefix_bar prefix_foo

但是,对函数执行此操作似乎需要过滤 set 的输出 - 这是一种更加随意的方法。

有正确的方法吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

哎呦我呸! 2024-09-05 03:47:06

compgen 怎么样:

compgen -A function   # compgen is a shell builtin

How about compgen:

compgen -A function   # compgen is a shell builtin
寻梦旅人 2024-09-05 03:47:06
$ 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
$ 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
(り薆情海 2024-09-05 03:47:06

我的 .bashrc 中有一个条目表示:

alias list='declare -F |cut -d" " -f3'

这允许我输入 list 并获取函数列表。当我加上去的时候,我大概明白发生了什么,但此刻我不记得要救我的命。

祝你好运,

--杰德

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

獨角戲 2024-09-05 03:47:06

这对于 IFS 和通配符都没有问题:

readarray -t funcs < <(declare -F)

printf '%s\n' "${funcs[@]##* }"

当然,这需要 bash 4.0。

对于 2.04 以后的 bash 使用(有点棘手但等效):

IFS=

如果您需要此选项的退出代码为零,请使用:

IFS=

如果 declare 它将退出不成功(不是 0) >读取失败。 (感谢@CharlesDuffy

\n' read -d '' -a funcs < <(declare -F)

如果您需要此选项的退出代码为零,请使用:


如果 declare 它将退出不成功(不是 0) >读取失败。 (感谢@CharlesDuffy

\n' read -d '' -a funcs < <( declare -F && printf '\0' )

如果 declare它将退出不成功(不是 0) >读取失败。 (感谢@CharlesDuffy

\n' read -d '' -a funcs < <(declare -F)

如果您需要此选项的退出代码为零,请使用:

如果 declare它将退出不成功(不是 0) >读取失败。 (感谢@CharlesDuffy

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=

If you need that the exit code of this option is zero, use this:

IFS=

It will exit unsuccesful (not 0) if either declare or read fail. (Thanks to @CharlesDuffy)

\n' read -d '' -a funcs < <(declare -F)

If you need that the exit code of this option is zero, use this:


It will exit unsuccesful (not 0) if either declare or read fail. (Thanks to @CharlesDuffy)

\n' read -d '' -a funcs < <( declare -F && printf '\0' )

It will exit unsuccesful (not 0) if either declare or read fail. (Thanks to @CharlesDuffy)

\n' read -d '' -a funcs < <(declare -F)

If you need that the exit code of this option is zero, use this:

It will exit unsuccesful (not 0) if either declare or read fail. (Thanks to @CharlesDuffy)

遇见了你 2024-09-05 03:47:06

使用内建声明来列出当前定义的函数:

declare -F

Use the declare builtin to list currently defined functions:

declare -F
櫻之舞 2024-09-05 03:47:06

zsh (不是所要求的,但所有更通用的问题已作为此问题的重复项而关闭):

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

zsh only (not what was asked for, but all the more generic questions have been closed as a duplicate of this):

typeset -f +

From 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.

Example:

martin@martin ~ % cat test.zsh 
#!/bin/zsh

foobar()
{
  echo foobar
}

barfoo()
{
  echo barfoo
}

typeset -f +

Output:

martin@martin ~ % ./test.zsh
barfoo
foobar
东风软 2024-09-05 03:47:06

这会收集与任何模式列表匹配的函数名称列表:

functions=$(for c in $patterns; do compgen -A function | grep "^$c\$")

grep 将输出限制为仅与模式完全匹配。

查看 bash 命令 type 作为以下命令的更好替代方案。感谢查尔斯·达菲提供的线索。

下面使用它来回答人类而不是 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

这可以说违反了 Unix“做一件事”的哲学,但我不止一次感到绝望,因为 which 没有找到某个包应该包含的命令,我忘记了 shell 函数,所以我把它放在我的 .profile 中。

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.

初心未许 2024-09-05 03:47:06

一种(丑陋的)方法是 grep set 的输出:

set \
  | egrep '^[^[:space:]]+ [(][)][[:space:]]*

欢迎更好的方法。

\ | sed -r -e 's/ [(][)][[:space:]]*$//'

欢迎更好的方法。

One (ugly) approach is to grep through the output of set:

set \
  | egrep '^[^[:space:]]+ [(][)][[:space:]]*

Better approaches would be welcome.

\ | sed -r -e 's/ [(][)][[:space:]]*$//'

Better approaches would be welcome.

遗失的美好 2024-09-05 03:47:06

纯 Bash:

saveIFS="$IFS"
IFS=

然后,在 Bash 提示符下运行,作为显示 bash 完成函数的示例:

$ for i in ${funcs[@]}; do echo "$i"; done
__ack_filedir
__gvfs_multiple_uris
_a2dismod
. . .
$ echo ${funcs[42]}
_command
\n' funcs=($(declare -F)) # create an array IFS="$saveIFS" funcs=(${funcs[@]##* }) # keep only what's after the last space

然后,在 Bash 提示符下运行,作为显示 bash 完成函数的示例:

Pure Bash:

saveIFS="$IFS"
IFS=

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
\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:

行至春深 2024-09-05 03:47:06
#!/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"
#!/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"
留蓝 2024-09-05 03:47:06

由于其他一些想要执行相同操作但在 POSIX shell 环境中的问题已作为重复项关闭而没有一个好的答案,因此我想我可以在此处添加一个 POSIX 兼容的变体。

注意:
Posix 并不包含所有的规则,并且实现仍然可以以不同的方式工作(例如 setgrep -o,请参阅注释)。这个答案是我能做的最好的事情,以获得一种兼容的方式来完成提问者的要求,但对于特定的平台,您可能需要使用这些命令。

如果您运行不带任何参数的 set 命令,它将列出任何 POSIX 环境中的所有可用函数,包括它们的实现。无论您如何定义它,输出的格式都是一致的,因此您可以可靠地 grep 输出如下所示的函数名称部分:

set | grep '^[a-zA-Z_][a-zA-Z0-9_]\+[[:space:]]\+()'

这将返回如下列表:

func1 () 
func2 () 
func3 () 

说明:您基本上是 grep 搜索表示字符串(仅包含有效字符),后跟空格,后跟 ()

如果您只想要名称,可以这样做:

set | grep '^[a-zA-Z_][a-zA-Z0-9_]\+[[:space:]]\+()' | sed "s/[[:space:]]\+.*$//"

这使用 sed 来删除名称后面的所有内容(可以使用 grep -o ,但该标志不一定是支持,见第一条评论)。

请注意,我们不能仅依赖于使用 grep,因为即使函数名称​​通常是行开头的唯一部分,它并不总是(例如,使用 HERE 字符串或类似的东西会使其变得很奇怪)。

Since some other questions that want to do the same but in a POSIX shell environment have been closed as duplicates without a good answer, I thought I might add a POSIX compatible variation here.

NOTICE:
Posix is not all-encompassing with it's rules and implementations can still work differently (like set and grep -o, see comments). This answer is the best I could do to get a compatible way to do what the question-asker asked, but for a specific platform you might have to play around with the commands.

If you run the set command without any arguments, it will list all available functions in any POSIX environment including their implementation. The output is in a format that is consistent regardless of how you defined it, so you can reliably grep out the function name parts like this:

set | grep '^[a-zA-Z_][a-zA-Z0-9_]\+[[:space:]]\+()'

This will return a list like this:

func1 () 
func2 () 
func3 () 

Explanation: You basically grep searches for a string (only including valid characters) followed by a space followed by ().

If you only want the names you can do it like this:

set | grep '^[a-zA-Z_][a-zA-Z0-9_]\+[[:space:]]\+()' | sed "s/[[:space:]]\+.*$//"

This uses sed to strip everything after the name (grep -o could be used, but the flag is not necessarily supported, see the first comment).

Notice we can not rely on using grep only, because even though the function name is usually the only part at the start of the line, it isn't always (for example with HERE strings or stuff like that make it weird).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文