Ubuntu22.04 编写一个带向导的sh脚本

采用逐次修改,最终完成代码的形式,以方便理解如何完成一段sh代码的编写。

1、确定需求:


1.1脚本1'fosh_install.sh'托管于GitHub,通过curl下载地址获得并直接运行
1.2运行'fosh_install.sh'时,通过检测/opt/FormID/sh/fosh.sh是否存在,若无则提示并创建目录,将这个目录加入$path变量,然后下载脚本2'fosh.sh'存至指定目录'/opt/FormID/sh'下,下载latest.version到'/opt/FormID/sh/fosh.version'提示用户退出后运行bash fosh.sh进入脚本,10s倒计时后退出。若/opt/FormID/sh/fosh.sh存在,下载GitHub上的latest.ver,读取latest_version存入$lv,读取/opt/FormID/sh/fosh.version中的$uv,比较,若有新版本,提示最新版本号以及询问是否更新脚本的版本,更新后变更$uv.
1.3用户运行'fosh.sh'时,若网络不通则提示,否则查询/opt/FormID/sh/fosh.version中的$if_updtae,值为yes则查询更新。然后列出功能清单,等待用户输入选择。
1.4主menu包含'1.安装常用工具'/'2.信息查询'/'3.设置是否更新FormID脚本'/'0.退出脚本';menu1包含'1.1 安装curl/net-tools等软件安装'/'1.2 docker 安装'/'1.3 Node.js v20安装'/'1.4 Python3.9安装'/'1.5 最新版pip安装'/'返回上一层';menu2 包含'2.1 实时系统进程查看htop'/'2.2 查看磁盘空间信息'/'2.3 查询Node.js版本'/'0 返回上一层'。

2、分析需求整理架构及运行逻辑

整理程序架构,定义功能functions,再把function填入架构当中(都说这是功能模块化),最后再美化美化。(先制作本地文件,涉及文件fosh_install.sh/fosh.sh/latest.version,完成后上传至GitHub。)ok,Go!Go!Go!

3、脚本架构

fosh.sh执行逻辑:

#!/bin/bash

# 定义函数1-判断与GitHub的网络连接是否通畅
check_github_connection() {
    echo "执行检查与GitHub的网络连接功能"
    # 在这里添加检查GitHub连接的具体逻辑
}

# 定义menu1_list
menu1_list() {
    # 提示用户进一步选择
    read -p "请选择以下选项:
    1. 子功能1
    2. 子功能2
    3. 子功能3
    0. 返回上一层
请输入数字(1-3,0): " menu1_sub_choice

    # 根据用户输入的数字调用相应的子函数或返回上一层
    case $menu1_sub_choice in
        1)
            echo "执行menu1子功能1"
            ;;
        2)
            echo "执行menu1子功能2"
            ;;
        3)
            echo "执行menu1子功能3"
            ;;
        0)
            echo "返回上一层。"
            ;;
        *)
            echo "无效的输入,输入必须为1、2、3或0。"
            ;;
    esac
}

# 定义menu2_list
menu2_list() {
    # 提示用户进一步选择
    read -p "请选择以下选项:
    1. 子功能1
    2. 子功能2
    3. 子功能3
    0. 返回上一层
请输入数字(1-3,0): " menu2_sub_choice

    # 根据用户输入的数字调用相应的子函数或返回上一层
    case $menu2_sub_choice in
        1)
            echo "执行menu2子功能1"
            ;;
        2)
            echo "执行menu2子功能2"
            ;;
        3)
            echo "执行menu2子功能3"
            ;;
        0)
            echo "返回上一层。"
            ;;
        *)
            echo "无效的输入,输入必须为1、2、3或0。"
            ;;
    esac
}

# 定义menu3函数
menu3() {
    echo "执行menu3函数"
    # 在这里添加menu3函数的具体逻辑
}

# 定义sh_exit函数
sh_exit() {
    echo "退出脚本"
    exit 0
}

# 定义打印主菜单的函数
print_main_menu() {
    echo "
    1. 安装常用工具
    2. 信息查询
    3. 设置是否自动检查更新FormID脚本
    0. 退出脚本"
}

# 主循环
while true; do
    print_main_menu
    # 提示用户输入1-4的数字
    read -p "请输入数字(0-3): " main_menu

    # 根据用户输入的数字调用相应的函数或退出脚本
    case $main_menu in
        1)
            check_github_connection
            ;;
        2)
            # 执行信息查询
            ;;
        3)
            # 执行设置是否自动检查更新FormID脚本
            ;;
        0)
            sh_exit
            ;;
        *)
            echo "无效的输入,输入必须为1、2、3或0。"
            ;;
    esac
done

4、处理各个涉及到的函数并添到相应的执行位置

4.1与GitHub之间的网络连接测测试Function

#定义检查本地与GitHub站点的连接状态
check_github_connection() {
    net_status="Failed"
    if curl --output /dev/null --silent --head --fail "https://www.github.com"; then
        net_status="OK"
        echo "你与GitHub站点的网络连接是 $net_status 的。"
    else
        net_status="Failed"
        echo "$net_status, 与GitHub的网络连接失败。"
    fi
}

# 执行检测
check_github_connection

4.2安装curl wget net-tools等常用软件

#定义安装curl wget net-tools等常用软件的Function
install_common_tools(){
apt-get update
clear
apt-get install -y curl wget net-tools ca-certificates gnupg htop nano screen git vim iproute2
clear
}
#执行Function
install_common_tools

4.3 10s后退出脚本的函数

#定义10s延时的的函数
delay_10s(){
    for i in {10..1}; do
        echo -ne "等待 $i 秒后返回...\r"
        sleep 1
    done
}

4.4Docker 安装的Function

#定义Docker安装的Function
install_docker(){
#删除之前安装的docker相关软件
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done

# 更新软件库数据源
apt-get update

#安装可能会使用上的软件
apt-get install ca-certificates curl gnupg

#安装gpg准备文件。
sudo install -m 0755 -d /etc/apt/keyrings

#下载gpg文件到指定目录
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

#变更gpg文件权限
sudo chmod a+r /etc/apt/keyrings/docker.gpg

#添加资源库到镜像源配置文件中
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
#更新软件库镜像源
sudo apt-get update
#安装docker docker-compose等
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin 
docker-compose docker-compose-plugin
#查看docker版本及docker-compose版本,以确定安装及运行情况,有无错返回数据即可。
clear
docker -v
docker-compose -v
echo "显示版本号即表示安装成功~~~"
delay_10s
}
#执行Function
install_docker

4.5安装Node.js v20

#定义安装Node.js v20的函数
install_nodejs20(){
#更新镜像源
sudo apt-get update
#安装必要的软件
sudo apt-get install -y ca-certificates curl gnupg
#创建gpg.key的存放目录
sudo mkdir -p /etc/apt/keyrings
#下载gpg.key并安装到指定目录
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
#设定版本变量
NODE_MAJOR=20
#获取并添加对应版本的的软件库源
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
#重新更新镜像源
sudo apt-get update
#安装nodejs
sudo apt-get install nodejs -y
clear
#查看node.js版本
nodejs -v
echo "显示版本号即表示安装成功~~~"
delay_10s
}
#执行Function
install_nodejs20

4.6安装Python3.9

#定义安装Python3.9的函数
install_python39(){
#更新镜像源
apt-get update
#安装software-properties-common
apt-get install software-properties-common
#添加python3的镜像源库、key,并更新一次镜像源
add-apt-repository ppa:deadsnakes/ppa
#安装python3.9
apt-get install python3.9 -y
clear
#查看python3版本
python3 -V
echo "显示版本号即表示安装成功~~~"
delay_10s
}
#执行Function
install_python39

4.7安装最新版pip

#定义安装最新版pip的函数
install_pip(){
#更新镜像源
apt-get update
#安装pip3
apt-get install python3-pip -y
#默认值可能是22.几,升级到最新
pip install pip -U
clear
#查看pip版本
pip -V
echo "显示版本号即表示安装成功~~~"
delay_10s
}
#执行Function
install_pip

5、把函数都放进结构中,调试一下,修正了之前的函数里面的错误。

#生成fosh.sh的功能脚本
#!/bin/bash

#定义检查本地与GitHub站点的连接状态
check_github_connection() {
    net_status="Failed"
    if curl --output /dev/null --silent --head --fail "https://www.github.com"; then
        net_status="OK"
        echo "你与GitHub站点的网络连接是 $net_status 的。"
    else
        net_status="Failed"
        echo "$net_status, 与GitHub的网络连接失败。"
    fi
}

#定义安装curl wget net-tools等常用软件的Function
install_common_tools(){
apt-get update
clear
apt-get install -y curl wget net-tools ca-certificates gnupg htop nano screen git vim iproute2
echo "常用软件已安装完成。"
delay_10s
clear
}

#定义10s延时的的函数
delay_10s(){
    for i in {10..1}; do
        echo -ne "等待 $i 秒后返回...\r"
        sleep 1
    done
}

#定义Docker安装的Function
install_docker(){
#删除之前安装的docker相关软件
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove -y $pkg; done

# 更新软件库数据源
apt-get update

#安装可能会使用上的软件
apt-get install -y ca-certificates curl gnupg

#安装gpg准备文件。
sudo install -m 0755 -d /etc/apt/keyrings

#下载gpg文件到指定目录
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

#变更gpg文件权限
sudo chmod a+r /etc/apt/keyrings/docker.gpg

#添加资源库到镜像源配置文件中
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
#更新软件库镜像源
sudo apt-get update
#安装docker docker-compose等
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose docker-compose-plugin
#查看docker版本及docker-compose版本,以确定安装及运行情况,有无错返回数据即可。

docker -v
docker-compose -v
echo "显示版本号即表示安装成功~~~"
delay_10s
clear
}

#定义安装Node.js v20的函数
install_nodejsv20(){
#更新镜像源
sudo apt-get update
#安装必要的软件
sudo apt-get install -y ca-certificates curl gnupg
#创建gpg.key的存放目录
sudo mkdir -p /etc/apt/keyrings
#下载gpg.key并安装到指定目录
sudo curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
#设定版本变量
NODE_MAJOR=20
#获取并添加对应版本的的软件库源
sudo echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
#重新更新镜像源
sudo apt-get update
#安装nodejs
sudo apt-get install -y nodejs

#查看node.js版本
nodejs -v
echo "显示版本号即表示安装成功~~~"
delay_10s
clear
}

#定义检查nodejs未安装或低于v20则安装node.js v20的函数
check_node_version(){
node_version=$(node -v 2>/dev/null)  # 获取 Node.js 版本,忽略错误信息
    if [ -n "$node_version" ]; then
        echo "已安装 Node.js,版本:$node_version"
        # 提取主版本号
        major_version=$(echo "$node_version" | cut -d. -f1)
        if [ "$major_version" -ge 20 ]; then
            echo "目前Node.js 版本为:$node_version,无需安装!"
            sleep 5
            exit 0
        else
            echo "Node.js 版本 < 20,即刻安装Node.js v20"
            sleep 5
            install_nodejsv20  # 如果版本小于 20,运行安装函数
        fi
    else
        echo "未安装 Node.js,即刻安装Node.js v20"
        sleep 5
        install_nodejsv20  # 如果未安装 Node.js,运行安装函数
    fi
}

#定义安装Python3.9的函数
install_python39(){
            clear

            RED="\033[31m"
            GREEN="\033[32m"
            YELLOW="\033[33m"
            NC="\033[0m"

            # 系统检测
            OS=$(cat /etc/os-release | grep -o -E "Debian|Ubuntu|CentOS" | head -n 1)

            if [[ $OS == "Debian" || $OS == "Ubuntu" || $OS == "CentOS" ]]; then
                echo -e "检测到你的系统是 ${YELLOW}${OS}${NC}"
            else
                echo -e "${RED}很抱歉,你的系统不受支持!${NC}"
                exit 1
            fi

            # 检测安装Python3的版本
            VERSION=$(python3 -V 2>&1 | awk '{print $2}')

            # 获取最新Python3版本
            PY_VERSION=$(curl -s https://www.python.org/ | grep "downloads/release" | grep -o 'Python [0-9.]*' | grep -o '[0-9.]*')
            # 卸载Python3旧版本
            if [[ $VERSION == "3"* ]]; then
                echo -e "${YELLOW}你的Python3版本是${NC}${RED}${VERSION}${NC},${YELLOW}最新版本是${NC}${RED}${PY_VERSION}${NC}"
                read -p "是否确认升级最新版Python3?默认不升级 [y/N]: " CONFIRM
                if [[ $CONFIRM == "y" ]]; then
                    if [[ $OS == "CentOS" ]]; then
                        echo ""
                        rm-rf /usr/local/python3* >/dev/null 2>&1
                    else
                        apt --purge remove python3 python3-pip -y
                        rm-rf /usr/local/python3*
                    fi
                else
                    echo -e "${YELLOW}已取消升级Python3${NC}"
                    exit 1
                fi
            else
                echo -e "${RED}检测到没有安装Python3。${NC}"
                read -p "是否确认安装最新版Python3?默认安装 [Y/n]: " CONFIRM
                if [[ $CONFIRM != "n" ]]; then
                    echo -e "${GREEN}开始安装最新版Python3...${NC}"
                else
                    echo -e "${YELLOW}已取消安装Python3${NC}"
                    exit 1
                fi
            fi
echo "卸载机器上的py完成。"
sleep 5
            # 安装相关依赖
            if [[ $OS == "CentOS" ]]; then
                yum update
                yum groupinstall -y "development tools"
                yum install wget openssl-devel bzip2-devel libffi-devel zlib-devel -y
            else
                apt update
                apt install wget build-essential libreadline-dev libncursesw5-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev libffi-dev zlib1g-dev -y
            fi

            # 安装python3
            cd /root/
            echo "此处指定版本号为3.9.0"
            sleep 5
            PY_VERSION=3.9.0
            wget https://www.python.org/ftp/python/${PY_VERSION}/Python-"$PY_VERSION".tgz
            echo "刚刚是获取压缩包"
            sleep 5
            tar -zxf Python-${PY_VERSION}.tgz
            cd Python-${PY_VERSION}
            ./configure --prefix=/usr/local/python3
            make -j $(nproc)
            make install
            if [ $? -eq 0 ];then
                rm -f /usr/local/bin/python3*
                rm -f /usr/local/bin/pip3*
                ln -sf /usr/local/python3/bin/python3 /usr/bin/python3
                ln -sf /usr/local/python3/bin/pip3 /usr/bin/pip3
                clear
                echo -e "${YELLOW}Python3安装${GREEN}成功,${NC}版本为: ${NC}${GREEN}${PY_VERSION}${NC}"
            else
                clear
                echo -e "${RED}Python3安装失败!${NC}"
                exit 1
            fi
            cd /root/ && rm -rf Python-${PY_VERSION}.tgz && rm -rf Python-${PY_VERSION}


#更新镜像源
#apt-get update
#安装software-properties-common
#apt-get install -y software-properties-common
#添加python3的镜像源库、key,并更新一次镜像源
#add-apt-repository ppa:deadsnakes/ppa
#安装python3.9
#apt-get install-y python3.9
#clear
#查看python3版本
python3 -V
echo "显示版本号即表示安装成功~~~"
delay_10s
}

#定义安装最新版pip的函数
install_pip(){
#更新镜像源
apt-get update
#安装pip3
apt-get install python3-pip -y
#默认值可能是22.几,升级到最新
pip install pip -U
clear
#查看pip版本
pip -V
echo "显示版本号即表示安装成功~~~"
delay_10s
}


#主程序函数定义开始~~~~


# 定义menu1_list
menu1_list() {
    # 提示用户进一步选择
    read -p "请选择以下选项:
    1. 安装curl wget net-tools等常用软件
    2. Docker 安装
    3. 安装Node.js v20
    4. 安装Python3.9
    0. 返回上一层
请输入数字(1-4,0): " menu1_sub_choice

    # 根据用户输入的数字调用相应的子函数或返回上一层
    case $menu1_sub_choice in
        1)
            install_common_tools
            ;;
        2)
            install_docker
            ;;
        3)
            check_node_version
            ;;
        4)
            install_python39
            ;;
        0)
            echo "返回上一层。"
            ;;
        *)
            echo "无效的输入,输入必须为1、2、3、4或0。"
            ;;
    esac
}


# 定义menu2_list
menu2_list() {
    # 提示用户进一步选择
    read -p "请选择以下选项:
    1. 实时系统进程查看
    2. 查看磁盘空间信息
    3. 查询Node.js版本
    0. 返回上一层
请输入数字(1-3,0): " menu2_sub_choice

    # 根据用户输入的数字调用相应的子函数或返回上一层
    case $menu2_sub_choice in
        1)
            htop
            ;;
        2)
            df -h
            delay_10s
            ;;
        3)
            node_version=$(node -v 2>/dev/null)  # 获取 Node.js 版本,忽略错误信息
            if [ -n "$node_version" ]; then
                echo "已安装 Node.js,版本:$node_version"
                sleep 5
            else
                echo "本机未安装任何版本的 Node.js"
                sleep 5
            fi
            ;;
        0)
            echo "返回上一层。"
            ;;
        *)
            echo "无效的输入,输入必须为1、2、3或0。"
            ;;
    esac
}

# 定义设置是否更新FormID脚本函数
check_update() {
    #"询问是否设置检查"
    read -p "请选择以下选项:
    e. 开启每次启动检测并自动更新本脚本
    d. 查看磁盘空间信息
    0. 返回上一层
请输入数字(1-3,0): " check_update_sub_choice

    # 根据用户输入的数字调用相应的子函数或返回上一层
    case $check_update_sub_choice in
        1)
            echo "开启自动更新本脚本。"
            sleep 5
            ;;
        2)
            echo "禁用自动更新本脚本。"
            sleep 5
            ;;
        0)
            echo "返回上一层。"
            ;;
        *)
            echo "无效的输入,输入必须为e、d或0。"
            ;;
    esac
}


# 定义sh_exit函数
sh_exit() {
    echo "退出脚本"
    exit 0
}

# 定义打印主菜单的函数
print_main_menu() {
    echo "
    1. 安装常用工具
    2. 信息查询
    3. 设置是否自动检查更新FormID脚本
    0. 退出脚本"
}

# 主程序开始
clear
check_github_connection
sleep 3
while true; do
    print_main_menu
    # 提示用户输入1-4的数字
    read -p "请输入数字(0-3): " main_menu

    # 根据用户输入的数字调用相应的函数或退出脚本
    case $main_menu in
        1)
            menu1_list
            ;;
        2)
            menu2_list
            ;;
        3)
            check_update
            ;;
        0)
            sh_exit
            ;;
        *)
            echo "无效的输入,输入必须为1、2、3或0。"
            ;;
    esac
done