Bash Shell 脚本/Shell 函数
Shell 函数是一种特殊类型的变量,本质上是脚本中的脚本。此功能允许我们将一系列命令分组到单个命名命令中,这在需要在脚本中的多个位置运行一系列命令时特别有用。Shell 函数甚至可以仅包含单个命令;如果命令特别复杂,或者其重要性不会立即对读者显而易见,这可能很有用。(也就是说,Shell 函数可以服务于两个目的:它们可以节省输入,并且可以通过创建直观的命名命令来使代码更易读。)请考虑以下脚本
#!/bin/bash
# Usage: get_password VARNAME
# Asks the user for a password; saves it as $VARNAME.
# Returns a non-zero exit status if standard input is not a terminal, or if the
# "read" command returns a non-zero exit status.
get_password() {
if [[ -t 0 ]] ; then
read -r -p 'Password:' -s "$1" && echo
else
return 1
fi
}
get_password PASSWORD && echo "$PASSWORD"
以上脚本创建了一个名为get_password
的 Shell 函数,它要求用户输入密码并将结果存储在指定的变量中。然后它运行get_password PASSWORD
将密码存储为$PASSWORD
;最后,如果对get_password
的调用成功(由其退出状态决定),则检索到的密码将被打印到标准输出(这显然不是实际用途;这里的目标只是为了演示get_password
的行为)。
函数get_password
没有做任何在没有 Shell 函数的情况下做不到的事情,但结果更易读。该函数调用内置命令read
(它读取一行用户输入并将其保存在一个或多个变量中)以及大多数 Bash 程序员不熟悉的一些选项。(-r
选项禁用反斜杠字符的特殊含义;-p
选项导致在行首显示指定的提示,在本例中为Password:
;-s
选项阻止用户键入的密码显示。由于-s
选项还会阻止用户的新行显示,因此echo
命令提供了一个新行。)此外,该函数使用条件表达式-t 0
来确保脚本的输入来自终端(控制台),而不是来自文件或另一个不知道正在请求密码的程序。(这个最后的特性是可争议的;根据脚本的总体功能,最好接受来自标准输入的密码,无论其来源如何,假设源是考虑到脚本而设计的。)总的来说,给一系列命令命名——get_password
——使程序员更容易了解它所做的事情。
在 Shell 函数中,位置参数($1
、$2
等等,以及$@
、$*
和$#
)是指调用函数时传递的参数,而不是包含该函数的脚本的参数。如果需要后者,则需要使用"$@"
显式地将它们传递给函数。(即使那样,shift
和set
也会只影响函数中的位置参数,而不是调用者的位置参数。)
函数调用会返回退出状态,就像脚本(或几乎任何命令)一样。要显式指定退出状态,请使用return
命令,它会终止函数调用并返回指定的退出状态。(exit
命令不能用于此目的,因为它会终止整个脚本,就像在函数外部调用它一样。)如果未指定退出状态,无论是由于未向return
命令提供任何参数,还是由于在未运行return
命令的情况下到达函数的末尾,则函数将返回上次运行命令的退出状态。
顺便说一句,function
或( )
可以从函数声明中省略,但必须至少存在一个。许多程序员编写get_password()
,而不是function get_password ( )
。类似地,{ … }
符号并不是严格要求的,也不是特定于函数的;它只是将一系列命令组合成单个复合命令的符号。函数的主体必须是复合命令,例如{ … }
块或if
语句;{ … }
是传统的选择,即使它只包含一个复合命令,并且理论上可以省略。