我编写了几组脚本来使 Linux 的设置变得非常简单。因此,我将这些脚本制作成单独的函数,并将其全部放在一个脚本中。我设置了数字,因此当用户输入其中一个数字时,它将调用该函数。然而,当用户输入一个数字时,脚本将调用所有函数:
n=1
#note you need spaces between [ ]
while [ $n == 1 ]
do
echo "Base install=1"
echo "Mintrepos=2"
echo "Asusn13 driver=3"
echo "Install Standard openbox=4"
echo "Install Xfceopenbox=5"
echo "backing up standard open box config=6"
echo "backing up openboxfce=7"
echo
read choice
if [ "$choice"==1 ]
then
baseinstall
fi
if [ "$choice"==2 ]
then
linuxmintrepos
fi
if [ "$choice"==3 ]
then
asusn13driver
fi
if [ "$choice"==4 ]
then
standardopenbox
fi
if [ "$choice"==5 ]
then
xfceopenbox
fi
if [ "$choice"==6 ]
then
backupstandopenbox
fi
if [ "$choice"==7 ]
then
backupxfc4openbox
fi
echo "You installed: "
if [ "$choice"==1 ]
then
echo "baseinstall"
fi
if [ "$choice"==2 ]
then
echo "linuxmintrepos"
fi
if [ "$choice"==3 ]
then
echo asusn13driver
fi
if [ "$choice"==4 ]
then
echo "standardopenbox"
fi
if [ "$choice"==5 ]
then
echo "xfceopenbox"
fi
if [ "$choice"==6 ]
then
echo "backupstandopenbox"
fi
if [ "$choice"==7 ]
then
echo "backupxfc4openbox"
echo "If you would like to keep going, type in 1, if not, type in any other number"
read n
fi
done
答案1
代替:
if [ "$choice"==1 ]
和:
if [ "$choice" = 1 ]
对所有后续测试执行相同的操作。
解释
当 shell 看到 时"$choice"==1
,它看到的是一个字符串。例如,如果choice
是 2,那么它会看到字符串2==1
。这不是平等测试。它是一个字符串。由于它是一个非空字符串,因此测试返回 true。因此所有的选择都会被执行。
为了识别相等测试,需要空格。
另外,作为一个小要点,对于[
样式测试,相等的符号是=
。 bash 会接受==
这一点,但它不正确,并且在其他 shell 中不起作用。
探索[...]
命令行上的测试
探索[
测试如何在命令行上工作很容易。首先,我们来演示一下空字符串测试为 false:
$ if [ "" ]; then echo True; else echo False; fi
False
非空字符串,无论它是什么,都是 true:
$ if [ abc ]; then echo True; else echo False; fi
True
现在,让我们看看2==1
:
$ if [ 2==1 ]; then echo True; else echo False; fi
True
由于2==1
是一个非空字符串,因此测试为 true。
现在,让我们添加空格并进行相等性测试:
$ if [ 2 = 1 ]; then echo True; else echo False; fi
False
$ if [ 2 = 2 ]; then echo True; else echo False; fi
True
作为一个额外的微妙之处,=
测试字符串相等性在这里恰好工作得很好。要测试数字相等性,请改用-eq
。
$ if [ 2 -eq 2 ]; then echo True; else echo False; fi
True
答案2
正如其他人提到的,您的if test ...;fi
陈述在语法上是不正确的,但值得注意的是您的整个方法有点粗糙。这个脚本的流程有几个方面可以得到极大的改进——特别是以后的阅读和编辑会更容易。
首先,您可以在循环set
中迭代地进行选择for
。这样任何可能的选择将向用户宣布并自动生成其选择器,但在脚本中您可以将它们全部集中在一个字符串列表中,而不必担心:
set --
for c in \
"Base install:base_fn" \
"Mintrepos:mint_fn" \
"Asusn13 driver:asus_fn" \
"Install Standard openbox:std_obox_fn" \
"Install Xfceopenbox:xfce_obox_fn" \
"backing up standard open box config:bkup_fn obox" \
"backing up openboxfce:bkup_fn xfce"
do
set -- "$@" "${c##*:}"
printf "'%s' = $#\n" "${c%:*}"
done
这会将调用编码fn_name
到位置参数数组中,同时将用户友好的描述打印到标准输出。
一旦您构建了选择列表"$@"
并在执行此操作时打印了进度,您就可以read
在一个小循环中进行用户的选择,该循环将在多次失败尝试后退出,同时还会验证其输入:
chk=$((($#<1)*5)) #if not at least one choice quit
until [ "$((chk+=1))" -gt 5 ] && exit 1 #chks up to 5 times or quits
printf '\nSelect: ' #prompts for each try
read -r c && [ -n "${c##*[!0-9]*}" ] #fails if input not number or empty
do echo "Invalid selection."; done #prints a notice and retries
最后你可以shift
去掉任何不必要的参数并调用$1
:
shift "$((c-1))"; $1
最好验证没有前导零。shift
如果用户选择的数字太高,就会出错。
[ "$((c=$(printf %.d "$c")))" -gt 0 ] || exit
shift "$((c-1))" && $1
这是针对数字选择列表的,这使得位置数组非常有用。更一般地,您可以使用以下case
语句:
case "$choice" in
(pattern 1) do as necessary for a match;;
(pattern 2) do otherwise for this match;;
(pattern 3) continue this wise for each;;
(*) until there isn't a match ;;
esac
这些只是模拟许多 shell 的便携式方法(包括bash
)将提供多年前select
介绍的声明。ksh
从man bash
:
select
姓名[in
单词];do
列表;done
- in 后面的单词列表被展开,生成一个项目列表。扩展单词集打印在标准错误上,每个单词前面都有一个数字。如果在言语中省略,位置参数(或者
"$@"
)被打印(参见下面的参数)。然后显示提示$PS3
并从标准输入读取一行。
- in 后面的单词列表被展开,生成一个项目列表。扩展单词集打印在标准错误上,每个单词前面都有一个数字。如果在言语中省略,位置参数(或者
答案3
您需要在==
.否则,您将字符串"$choice"==1
本身传递给if
而不是与 进行$choice
比较1
。当[
接收到一个字符串时,只要该字符串非空,它就会计算为 true:
$ foo="bar"; [ $foo ] && echo true
true
$ foo=""; [ "$foo" ] && echo true ## echoes nothing
在test
括号之外,如果没有空格,变量实际上会被分配给=1
。为了显示:
$ f==3
$ echo $f
=3
$ [ 10==12 ] && echo yes
yes
正如您在上面看到的,f==3
将变量设置$f
为=3
。
因此,在您的if
块中,正在测试的是一个非空字符串,它始终评估为 true 并且被if
执行。这会起作用:
if [ "$choice" == "1" ]
then
baseinstall
fi
另外,=
或者==
做字符串比较在bash中。你想要算术比较:
if [ "$choice" -eq "1" ]
then
baseinstall
fi