在Bash中简化动态菜单

时间:2017-07-20 19:46:31

标签: bash

我正在开发一个自定义bash脚本(我有非常的经验),我正在寻找一些菜单功能的帮助。我的脚本有几个不同的菜单完成不同的功能,所以我决定创建一个菜单功能,可以调用和设置变量自定义。这是不洁净和丑陋的,但我学到了很多东西。任何人都可以阐明我可以简化或以不同方式或更干净地完成工作的地方吗?提前谢谢!

#!/bin/bash

# set colors
red='tput setaf 1'
blue='tput setaf 4'
green='tput setaf 2'
bold='tput bold'
normal='tput sgr0'

# define function to reset screen to title
function reset {
    clear
    $bold
    $blue
    echo -e "lineage build script\n\n"
    $normal
    }

function title {
    reset
    $bold
    echo -e "$1\n"
    $normal
    }

# function to create menu
# menu "<title(required)>" "<question(required)>" <all(required)> "<option1>"...
# <title> - Page title
# <question> - Question to be posed before the menu
# <all> - Whether or not to present a menu choice for "All"
# <option#> - List of options to present to the user
function menu {
    # set input at 255 (max error level for return function later)
    input=255
    # check input to see if it's acceptable (within presented range and a number)
    while [[ $input -ge $(($counter+1)) ]] || [[ $((input)) != $input ]]; do
        # a call to a previously defind function establishing consistent page feel.
        title "$1"
        echo -e "$2"
        # present warning if input was invalid
        if ! [[ $input =~ "255" ]]; then
            $red
            echo -e "Invalid entry. Please try again.\n"
            $normal
        else
            echo -e "\n"
        fi
        counter=0
        # present list items for each variable passed to function starting at position 4
        # in order to skip the first 3 (title, question, all)
        for i in "${@:4}"; do
            counter=$(($counter+1))
            echo -e "$counter) $i"
        done
        # present "All" option if variable 3 is any form of yes
        if [[ $3 =~ (y|yes|Y|YES) ]]; then $green; counter=$(($counter+1)); echo -e "$counter) All"; $normal; fi
        # present "Exit" option
        $red; counter=$(($counter+1)); echo -e "$counter) Exit\n"; $normal
        # gather input
        read -N 1 -p "[1-$counter]: " input
    done
    # bail if exit was chosen
    if [[ $input == $counter ]]; then $red; echo -e "\nExit"; exit; fi
    # pass choice back to script as return code
    return $input
    }

# call the menu function for testing
menu "Main Menu" "What would you like to do?" y "option 1" "option 2" "option 3" "option 4" "option 5"
#echo return code just to verify function
echo -e "\nYou chose $?"

1 个答案:

答案 0 :(得分:0)

让我们看看这是否有助于(复古)。不仅是shell脚本相关。

  1. 命名
  2. reset函数是一个动词,而title则不是。但它可能是,表明它做了什么,它不是一个变量。

    1. 打印
    2. 您始终使用echo -e进行打印。正如Charles Duffy在下面的评论中指出的那样,您使用-e牺牲了POSIX兼容性。

        

      除非省略-n(作为第一个参数)和转义序列,否则无法在所有POSIX系统中使用echo。
        printf实用程序可以移植用于模拟echo实用程序的任何传统行为,如下所示(假设IFS具有其标准值或未设置)
        http://pubs.opengroup.org/onlinepubs/009696799/utilities/echo.html

      无论您将用于打印的实际方式如何:如何使其成为一种功能?如果你必须改变,这是一个去的地方。希望这不会引导您进入大量重载功能(针对各种打印选项)。

      1. 本地
      2. 我喜欢你的程序的一个原因是你将变量放在它们所属的位置,本地保存到函数中。也许你可以通过实际表示(在合理的地方)将它们本地化来实现这一目标。

        local [option] name[=value]
        

        https://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html

        1. 要继续前一点,我通常更喜欢将有序参数存储/移动到局部变量。例如title_text=$1。在menu函数中,它允许您使用shift。您将处理“标题”,“菜单名称”和“所有”选项,然后您最终只能使用$@变量中的选项列表。选项名称列表。如果您以后想要重构函数的某些部分(不破坏顺序)或者您希望将所述列表传递给另一个函数来处理选项,则非常方便。

          shift [n]
          
            

          将位置参数向左移动n。位置   来自n + 1 ... $#的参数被重命名为$ 1 ... $# - n。参数   由$#到$# - n + 1的数字表示未设置。 n必须是   非负数小于或等于$#。如果n为零或更大   比$#,位置参数不会改变。如果n不是   如果提供,则假定为1.除非n为,否则返回状态为零   大于$#或小于零,否则为非零。

          https://www.gnu.org/software/bash/manual/html_node/Bourne-Shell-Builtins.html

          1. 退出代码
          2. 我已经找到了回归值(退出代码)的使用方法。有点可惜的是,当你拨打exit时,唯一不使用它的情况就是实际情况。我的意思是,如果不进入menu函数,我会感到困惑,为什么如果我“退出”,为什么我从未看到“你选择”。