为什么我的脚本调用多个函数?

为什么我的脚本调用多个函数?

我编写了几组脚本来使 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并从标准输入读取一行。

答案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

相关内容