我正在寻找类似于 Bash 内置的东西,command
如果它是一个函数,它只会运行一些东西。所以目前我有一种不安全的做法:
# Go through arguments in order
for i in $*; do
if [ -z `which $i` ]; then
# Run function
$i && echo -n ' '
fi
done
这个 if 语句不能正常工作。无论如何,即使我可以检查它是否是命令而不是函数,我也无法显式运行函数,这很糟糕,因为如果有人在 $PATH 中有任何与我的函数同名的程序,它们将被跑步。如果我取消 PATH 或将其设置为其他任何内容,任何人仍然可以使用 $i 显式运行程序,所以这也不是解决方案。
有什么办法可以“保护”我的 shell 脚本吗?
答案1
使用bash
,您可以执行以下操作:
for f do
if declare -F -- "$f" >/dev/null 2>&1; then
: "$f" is a function, do something with it
fi
done
declare -F -- "$f" >/dev/null 2>&1
$f
如果是 bash 函数,将返回成功代码,不输出任何内容。
bash
在POSIX 模式下运行时,您可能还想通过添加builtin enable -n -- "$f"
.
答案2
Bash 提供的正式方法是使用type
内置的 as of type -t
:
function fun() {
: foo bar
}
if [ function = $(type -t fun) ]; then
echo fun is a function.
fi
如果您对参数列表中的函数名称有疑问,只需用双引号引起来即可:$(type -t "$arg")
答案3
虽然您可能已经在bash
shell 中设置好了,但要进行类似的可移植操作,您可能会使用类似以下的内容......
eval " for c in $(unalias -a
for c do case ${c#function} in
(*[!_[:alnum:]]*) ;; (?*)
PATH= command -v "$c" >&2 &&
PATH= command -V "$c" &&
printf '\n'"'$c'"'\\\0'
esac 2>/dev/null; done |
tr '\t\n\0' ' \n' |
sed -ne's/.* function .* / /p')"'
;do "$c"; printf %02s
done'
它分阶段进行:
- 首先清除所有包含任何字符的参数,这些字符可能会使它们首先失去作为 shell 名称的资格。
- 如果当前 arg 是有效名称和有效的 shell 内置函数或函数将其名称和类型打印到标准输出。由于 shell 可以改变其输出的方式,因此
command -V
不能将其输出视为一行。因此,输出后面带有我们验证的名称和空字节。 tr
将所有换行符和制表符转换为空格,并将所有空字节转换为换行符。- ,替换掉所有行中最后一个空格字符,如果该行也与字符串匹配则打印
sed
结果s///
function
。 - 所有 的
sed
输出都作为外循环的迭代器向上舍入for
,每个迭代器依次执行,并且在每个执行后printf
写出两个空格。