我对 Bash shell 脚本非常陌生,最终我得到了以下代码。我无法让它以任何其他方式工作,但我觉得这是非常草率的代码。
有人可以帮我用惯用的(安全、简洁、易于阅读)Bash 重新编写这段代码吗?我特别想知道是否有更好的方法从函数返回值,以及我是否在 if 语句中正确测试它。 (if 语句应该使用括号吗?)
#!/bin/bash
input() {
read -p $'\e[31m\e[1m'"$1"$' [Y/n] \e[0m' -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]
then
return 0
fi
return 1
}
if input "Upgrade Arch?"
then
sudo pacman -Syu
fi
答案1
您可以简单地在语句中结束函数,然后函数的返回码将是语句本身的返回码。
支票[[ $REPLY =~ ^[Yy]$ ]]
看起来不错。由于您使用的是 bash 内置双方括号测试,因此不需要引用变量,因为它们内部不会发生分词。使用正则表达式检查很好,尽管更简单的全局匹配[[ $REPLY = [Yy] ]]
也可以。
我想我要做的主要其他更改是在函数中使用局部变量并将其传递给read
.您可以将其标记为 atlocal
或 use declare
,这使得变量在函数内部使用时成为局部变量。
最后一点是,您可能需要考虑在脚本中启用选项errexit
( -e
)、nounset
( -u
) 和以使它们更安全。pipefail
这将阻止脚本在命令失败后继续运行,并有助于捕获变量名称中的拼写错误。在这些情况下,您需要更加防御性地进行编码(显式测试大多数命令中的错误,使用可能未设置的环境变量的默认值),但是当出现意外中断时,它可以更轻松地进行调试。
把它们放在一起:
#!/bin/bash
set -eu -o pipefail
input() {
declare confirm
declare -r prompt=${1:-"Confirm?"}
read -p $'\e[31m\e[1m'"${prompt}"$' [Y/n] \e[0m' -n 1 -r confirm
echo
[[ $confirm =~ ^[Yy]$ ]]
}
if input "Upgrade Arch?" ; then
sudo pacman -Syu
fi
并作为@StéphaneChazelas建议,您甚至可以进一步改进它:
set -eu -o pipefail
input() {
declare confirm
declare -r prompt=${1:-"Confirm?"}
IFS= read -p $'\e[31;1m'"${prompt}"$' [Y/n] \e[m' -n 1 -r confirm
echo >&2
[[ $confirm = [Yy] ]]
}
if input "Upgrade Arch?" ; then
sudo pacman -Syu
fi