我有以下代码:
#!/bin/sh
g_yes=0
g_no=-1
g_cancel=1
g_none=127
show_yes_no_prompt()
{
rc=$g_none
prompt=$*
while true; do
read -p $prompt"(ync): "
case $yn in
[Yy]* ) rc=$g_yes; break;;
[Nn]* ) rc=$g_no; break;;
[Cc]* ) rc=$g_cancel; break;;
* ) echo "Please answer yes/no/cancel.";;
esac
done
return $rc
}
install_pkg()
{
pkg_name=$*
prompt="Install "$pkg_name"?"
show_yes_no_prompt $prompt
if [ $? -eq $g_cancel ]; then
exit 0
fi
if [ $? -eq $g_yes ]; then
apt-get install -y $pkg_name
else
echo "Installation of "$pkg_name" refused."
fi
}
当我写install_pkg package1 package2
时,提示只会显示'Install',但我需要提示符如'Install package1 package2'。那么,这段代码出了什么问题?
答案 0 :(得分:1)
这是错误的界限:
read -p $prompt"(ync): "
$prompt
包含空格,因此read
只会占用$prompt
的第一个单词。解决方案是将$prompt
括在"
中,以确保它是一个完整的字符串。
替换为
read -p "$prompt (ync): " yn
通常,在bash中对字符串使用"
时,您可以直接使用变量。无需拆分字符串。如果您不想要空格,可以像下面这样限制变量的名称:
read -p "${prompt}(ync): " yn
答案 1 :(得分:1)
你引用的事情都很混乱。您想引用变量扩展。
所以你想要prompt="Install $pkg_name?"
和show_yes_no_prompt "$prompt"
等,而不是prompt="Install "$pkg_name"?"
和show_yes_no_prompt $prompt
。
这里发生的事情是,您将$prompt
的每个单词作为单独的参数传递给show_yes_no_prompt
(这很好,因为您将它们全部粘贴到$*
一起虽然注意到你无法以这种方式正确处理名称中包含空格的包,但是该函数。
问题是当你在函数中使用$prompt
而不引用它时它会再次被分开,因此read
的{{1}}参数只看到第一个单词,并显示它显示的全部(然后由于-p
不是有效的标识符而被你的“变量名称”弄糊涂了。
您也不会将pkg(ync)
作为参数读取,因此它不会将其读取的值分配给那里。
脚本的更正版本如下。
yn
注意我是如何使用数组在#!/bin/sh
g_yes=0
g_no=-1
g_cancel=1
g_none=127
show_yes_no_prompt()
{
rc=$g_none
while true; do
read -r -p "$* (ync): " yn
case $yn in
[Yy]* ) rc=$g_yes; break;;
[Nn]* ) rc=$g_no; break;;
[Cc]* ) rc=$g_cancel; break;;
* ) echo "Please answer yes/no/cancel.";;
esac
done
return $rc
}
install_pkg()
{
pkgs=("$@")
show_yes_no_prompt "Install ${pkgs[*]}?"
if [ $? -eq $g_cancel ]; then
exit 0
fi
if [ $? -eq $g_yes ]; then
apt-get install -y "${pkgs[@]}"
else
echo "Installation of ${pkgs[*]} refused."
fi
}
函数中存储$@
的。这是正确/安全地处理任意包名称的唯一方法。
install_pkg
的{{1}}参数几乎总是您想要的,并阻止-r
解释/吞咽反斜杠转义。
另请注意,一般情况下,read
扩展比read
扩展更可取(并应始终引用),除非将扩展放在需要单个字符串的字符串中例如@
扩展是必要的。)
另请注意,您永远不会从函数中获取*
。你会得到*
。