如果我有一个文件:
dome.sh
$ls -l dome.sh
-rwxrwxr-x 1 user user 0 Aug 8 11:19 dome.sh
文件内容类似如下:
#!/bin/bash
function() {
'work'
}
another() {
'different work'
}
...
#30 functions later
yetANOTHERfunction () {
'even more work'
}
其中“#30 个函数后续”表示有 30 个独特的附加函数
我能否以某种方式遍历该脚本中的所有函数来识别它们?
就像是:
for i in $(get all functions in this file); do
echo $i
done
生产:
function
another
...
yetANOTHERfunction
答案1
如果将“declare -F”中的“F”大写,那么它将返回类似“declare -f functionName”的行。现在您需要做的就是删除该行的第一部分。以下是代码:
#!/bin/bash
function () {
return
}
another () {
return
}
yetANOTHERfunction () {
return
}
IFS=$'\n'
for f in $(declare -F); do
echo "${f:11}"
done
答案2
尝试:
get_fcn_list () {
env -i bash --noprofile --norc -c '
source "'"$1"'"
typeset -f |
grep '\''^[^{} ].* () $'\'' |
awk "{print \$1}" |
while read -r fcn_name; do
type "$fcn_name" | head -n 1 | grep -q "is a function$" || continue
echo "$fcn_name"
done
'
}
for fcn_name in $(get_fcn_list dome.sh); do
echo "$fcn_name"
done
解释:
您不需要自己解析函数,而是让我们
bash
解析它们(使用source
)并转储内容(typeset -f
)。该调用
env -i bash --noprofile --norc
旨在防止bash
读取任何初始化文件。否则,您可能会得到在例如中定义的函数~/.bashrc
。typeset -f
将转储所有函数及其定义。每个定义都以以下内容开头:函数名称,空间,,()
空间,新队.grep
并awk
从这些行中提取函数名称。使用过滤器的原因是,当您具有以下功能时,可能会得到误报:
f () { echo " a () " }
这里,
while
循环会错误地打印a
,但过滤器会处理这个问题。编辑以从文件打印功能,并避免包含启动文件。
答案3
我尝试过这里提出的解决方案,但都有缺陷:
- 我见过bashBedlam 的解决方案在对类似问题的几个回答中(例如这个),但是,尽管它们很受欢迎,但它们都是错误的,因为简单调用
declare -F
(或等效调用)不会列出脚本文件中明确声明的函数,它们还会列出从父 shell 导出的函数!需要一个干净的环境来防止外部声明干扰。 - Matei David 的解决方案考虑到环境的副作用(非常好),但不必要地复杂化(为什么要通过仅提供那些名称来过滤整个函数定义输出
typeset -f
?declare -F
);除此之外,它不会保护其输出免受源脚本可能的标准输出的影响。
这是我的解决方案(感谢 Matei David 提供env/bash call
):
get_fcn_list () {
env -i bash --noprofile --norc -c '
source "'"$1"'" >/dev/null
while read -r line; do
echo ${line##* }
done < <(declare -F)
'
}
for fcn_name in $(get_fcn_list dome.sh); do
echo "$fcn_name"
done