这是我的代码:
function update_profile
{
echo "1. Update Name"
echo "2. Update Age"
echo "3. Update Gender"
echo "Enter option: "
read option
case $option in
1) update_name ;;
2) update_age ;;
3) update_gender ;;
esac
function update_name
{
echo "Enter new name: "
read name
}
}
只是想确定是否可以这样做。我确实知道我可以将所有代码放入案例中,但这会很混乱,所以我想在函数内创建一个独立的函数,并在需要执行其命令时调用。
答案1
是的,这是可能的。
甚至可以将一个函数嵌套在另一个函数中,尽管这不是很有用。
f1 ()
{
f2 () # nested
{
echo "Function \"f2\", inside \"f1\"."
}
}
f2 # Gives an error message.
# Even a preceding "declare -f f2" wouldn't help.
echo
f1 # Does nothing, since calling "f1" does not automatically call "f2".
f2 # Now, it's all right to call "f2",
#+ since its definition has been made visible by calling "f1".
# Thanks, S.C.
来源:Linux 文档项目
答案2
您可以在 shell 需要命令的任何地方定义函数,包括在函数中。请注意,该函数是在 shell 执行其定义时定义的,而不是在 shell 解析文件时定义的。所以如果用户第一次update_profile
执行时选择选项1,你的代码将无法工作,因为在语句update_name
中调用when时case
,函数的定义update_name
还没有被执行。一旦函数update_profile
被执行一次,函数update_name
也将被定义。
您需要将 的定义移到update_name
使用它的位置之前。
定义update_name
insideupdate_profile
并不是特别有用。这确实意味着在第一次执行update_name
之前不会被定义,但之后它将保持可用。update_profile
如果您只想update_name
在内部可用update_profile
,请在其中定义函数并unset -f update_name
在从函数返回之前调用。不过,与做简单的事情并全局定义所有函数相比,这样做并不会真正获得任何好处。
答案3
是的,当您考虑 shell 函数的真正含义时,这一点就会变得更加清楚。
对于 POSIX 兼容的 shell,函数定义是标准化的:
2.9.5功能 定义 命令
- A功能是一个用户定义的名称,用作简单的命令打电话给复合命令与新的位置参数。函数是用“函数定义命令“... 如下:
fname() compound-command[io-redirect ...]
该函数被命名
fname
为...实现应维护单独的名称空间功能和变量。论据复合命令代表一个复合命令,如中所述复合命令。
- 当。。。的时候功能被宣布,没有一个扩展在单词扩展应根据
compound-command
或者<<&io-redirect&>
;每次调用该函数时,所有${expansions}
操作都应正常执行。同样,可选的<<&io-redirect&>
重定向和任何variable=assignments
之内compound-command
应在函数本身执行期间执行,而不是在函数定义期间执行。看Shell 错误的后果这些操作在交互式和非交互式 shell 上失败的后果。
- 当。。。的时候功能被宣布,没有一个扩展在单词扩展应根据
因此,从本质上讲,名为 name 的 shell 函数fname
是一个文字字符串,其中至少包含一个复合命令shell 将从内存中调用并执行,而不是fname
在输入中出现时执行指挥位置- 这意味着无论何时指令会做。这个定义为在 POSIX shell 中使用函数提供了很多可能性。以下任一情况均可接受:
fn() {
command; list;
fn() { : redefines itself upon first execution; }
}
...和...
fn() {
helper1() { : defines another function which it can call; }
helper2() { : and another; }
helper1 "$@" | helper2 "$@" #processes args twice over pipe
command "$@"; list; #without altering its args
}
但这只是一个小例子。如果你考虑的含义复合命令你可能会开始发现传统fn() { : cmds; }
形式只是单程一个函数可以工作。考虑一些不同类型的复合命令:
{ compound; list; of; commands;} <>i/o <i >o
(subshelled; compound; list; of; commands) <>i/o <i >o
if ...; then ...; fi <>i/o <i >o
case ... in (...) ...;; esac <>i/o <i >o
for ... [in ... ;] do ...; done <>i/o <i >o
(while|until) ...; do ....; done <>i/o <i >o
除此之外还有其他人。上述任何一项都应该像...
fname() compound list
...并且其中任何可以在未分配为函数时嵌套的内容仍然可以嵌套,即使定义为命令也是如此。
这是我编写函数的一种方法:
update_prof(){
cat >&3
read "${2-option}" <&3
case "${1-$option}" in
1) update_prof '' name ;;
2) update_prof '' age ;;
3) update_prof '' gender ;;
*) unset option ;;
esac
} <<-PROMPT 3<>/dev/tty
${1-
1. Update Name
2. Update Age
3. Update Gender
}
Enter ${2:-option}: $(
printf '\033%s' \[A @
)
PROMPT
关于上述内容的一些注意事项:
- in更新
read
受 IFS 和反斜杠解释的约束。很可能是这样,IFS= read -r "$1"
但我不确定你希望如何解释这些事情。在此网站上查找其他答案,以获得有关该分数的更多更好的信息。 - 此处
printf '\033%s...
文档中的 假设/dev/tty
链接到 VT100 兼容终端,在这种情况下,使用的转义应该阻止此处文档的最终换行符显示在屏幕上。鲁棒地tput
会被使用。在那里获取man termcap
更多信息。- 最好的是 VT100 假设是正确的,您可以不使用任何一个
printf
,也可以tput
直接在此处文档中输入转义字符,例如^V{esc}[A^V{esc}@
where^V
是表示组合键的一种方式CONTROL+V
,并且{esc}
是键盘的ESC
键。
- 最好的是 VT100 假设是正确的,您可以不使用任何一个
上面的函数将根据其参数集执行双重任务 - 它将执行两次并仅根据需要重新评估其提示 - 因此它不需要第二个函数 - 因为只要最初调用它,它就可以执行这两项操作首先没有参数。
所以如果我跑...
update_prof; printf %s\\n "$name"
随后的终端活动如下所示:
1. Update Name
2. Update Age
3. Update Gender
Enter option: 1
Enter name: yo mama
yo mama
答案4
我在这里重新添加杰夫·沙勒 (Jeff Schaller) 已删除的答案,以确保有一个答案表明确实存在用例,并且接受的答案暗示说“这不是很有用”本质上是错误的。
这里再次出现(修复以显示我的答案的意思):
它“不是很有用”吗?我认为这实际上很酷。
我的bashrc
/中有特定于项目的初始化函数bash_aliases
,它将我的环境初始化为给定的项目。
在此之前,我只是全局定义了所有别名和函数(诸如此类的快捷方式cdprojectname
) 。modulename_build
这样做的问题是,在处理很多项目后,您可以轻松地使用很长的名称来避免名称冲突。
所以我所做的是,我采取了cdprojectname
(就像cdsd
项目一样sd
),这是一个函数,不仅可以转到项目目录,而且可以在涉及项目时初始化我的所有开发环境。
在我看来,你可以创建一个定义 shell 函数的函数,这真是太酷了。当我从内部使用我的别名时,需要测试这是否有效vim
- 是的,我查了一下,我的技巧不起作用
- jaja 不管怎样,如果我现在从 vim 中发出它甚至不起作用
cdsd
- 仍然很酷的功能,因为它是!
至于对答案的评论
“请不要添加“谢谢”作为答案。一旦您拥有足够的声誉,您将能够投票选出您认为有帮助的问题和答案。 – Jeff Schaller”
抱歉,我无法写信给您,但我没有写我所写的内容作为感谢,但我从之前的评论/答案中看到,这些评论/答案并没有真正突出显示此功能的可能用例,有些人甚至说“甚至可以将一个函数嵌套在另一个函数中,虽然这不是很有用。”
这不是感恩节,而是想指出,这实际上不是“这不是很有用”,而是“非常非常有用且简洁的功能”,对于其他脚本/shell 语言来说实际上拥有它会很棒!
我发布了我的答案,因为非常不同意这不是很有用,但当前接受的答案暗示了这种方式......请编辑您想要的方式或只是保留它,否则我认为接受的答案中有错误信息/提示。