如何写一个简易的脚本安装器

wen 实用脚本 3

本文目录导读:

如何写一个简易的脚本安装器

  1. Bash Shell 脚本安装器(最常用)
  2. 交互式安装器(增强版)
  3. Python 安装器(跨平台)
  4. 自定义安装目录版本
  5. 使用建议

我来帮你写一个简易的脚本安装器,这里提供几种常见的实现方案:

Bash Shell 脚本安装器(最常用)

#!/bin/bash
# ============================================
# 简易脚本安装器
# 使用方法: ./install.sh
# ============================================
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 安装目录
INSTALL_DIR="/usr/local/bin"
SCRIPT_NAME="my_script.sh"
TEMP_DIR="/tmp/installer_$$"
# 显示帮助信息
usage() {
    echo "用法: $0 [选项]"
    echo "选项:"
    echo "  -d DIR    指定安装目录 (默认: $INSTALL_DIR)"
    echo "  -h        显示此帮助信息"
    echo "  -u        卸载程序"
}
# 检查是否以root运行
check_root() {
    if [[ $EUID -ne 0 ]]; then
        echo -e "${RED}错误: 请以root权限运行此安装器${NC}"
        exit 1
    fi
}
# 检查依赖
check_dependencies() {
    local deps=("curl" "wget" "tar")
    local missing=()
    for dep in "${deps[@]}"; do
        if ! command -v $dep &> /dev/null; then
            missing+=($dep)
        fi
    done
    if [ ${#missing[@]} -ne 0 ]; then
        echo -e "${YELLOW}警告: 缺少依赖包: ${missing[*]}${NC}"
        read -p "是否尝试自动安装? (y/n): " -n 1 -r
        echo
        if [[ $REPLY =~ ^[Yy]$ ]]; then
            # 根据系统类型安装
            if command -v apt-get &> /dev/null; then
                sudo apt-get update
                sudo apt-get install -y "${missing[@]}"
            elif command -v yum &> /dev/null; then
                sudo yum install -y "${missing[@]}"
            else
                echo -e "${RED}错误: 无法自动安装依赖${NC}"
                exit 1
            fi
        else
            echo -e "${RED}错误: 缺少必要依赖${NC}"
            exit 1
        fi
    fi
}
# 下载文件
download_files() {
    echo -e "${BLUE}[1/4] 下载文件...${NC}"
    # 假设文件从远程服务器下载
    local download_url="https://example.com/scripts/$SCRIPT_NAME"
    mkdir -p $TEMP_DIR
    # 使用curl或wget下载
    if command -v curl &> /dev/null; then
        curl -ksSL "$download_url" -o "$TEMP_DIR/$SCRIPT_NAME"
    elif command -v wget &> /dev/null; then
        wget --no-check-certificate -q -O "$TEMP_DIR/$SCRIPT_NAME" "$download_url"
    else
        echo -e "${RED}错误: 没有可用的下载工具${NC}"
        exit 1
    fi
    if [ $? -ne 0 ]; then
        echo -e "${RED}错误: 下载失败${NC}"
        cleanup
        exit 1
    fi
}
# 安装文件
install_files() {
    echo -e "${BLUE}[2/4] 复制文件到 $INSTALL_DIR${NC}"
    # 创建目标目录(如果不存在)
    mkdir -p "$INSTALL_DIR"
    # 复制文件
    cp "$TEMP_DIR/$SCRIPT_NAME" "$INSTALL_DIR/"
    # 设置执行权限
    chmod +x "$INSTALL_DIR/$SCRIPT_NAME"
    if [ $? -eq 0 ]; then
        echo -e "${GREEN}✓ 文件安装成功${NC}"
    else
        echo -e "${RED}✗ 文件安装失败${NC}"
        cleanup
        exit 1
    fi
}
# 创建配置
create_config() {
    echo -e "${BLUE}[3/4] 创建配置文件...${NC}"
    # 示例:创建配置文件
    if [ ! -f "/etc/my_script.conf" ]; then
        cat > "/etc/my_script.conf" << EOF
# 我的脚本配置
INSTALLED=true
VERSION=1.0.0
INSTALL_DATE=$(date)
INSTALL_DIR=$INSTALL_DIR
EOF
        echo -e "${GREEN}✓ 配置文件创建成功${NC}"
    else
        echo -e "${YELLOW}⚠ 配置文件已存在,跳过${NC}"
    fi
}
# 清理临时文件
cleanup() {
    echo -e "${BLUE}[4/4] 清理临时文件...${NC}"
    rm -rf $TEMP_DIR
}
# 卸载函数
uninstall() {
    echo -e "${YELLOW}卸载 $SCRIPT_NAME...${NC}"
    # 删除安装的文件
    if [ -f "$INSTALL_DIR/$SCRIPT_NAME" ]; then
        rm -f "$INSTALL_DIR/$SCRIPT_NAME"
        echo -e "${GREEN}✓ 已删除主程序${NC}"
    fi
    # 删除配置文件
    if [ -f "/etc/my_script.conf" ]; then
        rm -f "/etc/my_script.conf"
        echo -e "${GREEN}✓ 已删除配置文件${NC}"
    fi
    echo -e "${GREEN}卸载完成${NC}"
}
# 主函数
main() {
    # 解析命令行参数
    while getopts "d:hu" opt; do
        case $opt in
            d)
                INSTALL_DIR=$OPTARG
                ;;
            h)
                usage
                exit 0
                ;;
            u)
                uninstall
                exit 0
                ;;
            \?)
                usage
                exit 1
                ;;
        esac
    done
    # 显示欢迎信息
    echo -e "${GREEN}================================${NC}"
    echo -e "${GREEN}   简易脚本安装器 v1.0.0       ${NC}"
    echo -e "${GREEN}================================${NC}"
    echo
    # 检查root权限(可选的,如果不是必需权限则注释掉)
    # check_root
    # 检查依赖
    check_dependencies
    # 执行安装步骤
    download_files
    install_files
    create_config
    cleanup
    # 显示完成信息
    echo
    echo -e "${GREEN}================================${NC}"
    echo -e "${GREEN}   安装成功!               ${NC}"
    echo -e "${GREEN}================================${NC}"
    echo
    echo -e "安装位置: ${YELLOW}$INSTALL_DIR/$SCRIPT_NAME${NC}"
    echo -e "使用命令: ${YELLOW}$SCRIPT_NAME --help${NC}"
    echo -e "配置位置: ${YELLOW}/etc/my_script.conf${NC}"
    echo
}
# 执行主函数
main "$@"

交互式安装器(增强版)

#!/bin/bash
# ============================================
# 交互式脚本安装器
# ============================================
# 日志函数
log_info() {
    echo -e "\033[1;34m[INFO]\033[0m $1"
}
log_success() {
    echo -e "\033[1;32m[SUCCESS]\033[0m $1"
}
log_warn() {
    echo -e "\033[1;33m[WARN]\033[0m $1"
}
log_error() {
    echo -e "\033[1;31m[ERROR]\033[0m $1"
}
# 进度条函数
show_progress() {
    local current=$1
    local total=$2
    local bar_len=40
    local fill_len=$((current * bar_len / total))
    printf "["
    for ((i=0; i<fill_len; i++)); do
        printf "█"
    done
    for ((i=fill_len; i<bar_len; i++)); do
        printf " "
    done
    printf "] %d%%" $((current * 100 / total))
    echo
}
# 确认函数
confirm() {
    read -p "$1 (y/n): " -n 1 -r
    echo
    [[ $REPLY =~ ^[Yy]$ ]]
}
# 安装选项
install_options() {
    echo "====================="
    echo "请选择要安装的组件:"
    echo "====================="
    read -p "是否安装核心组件? (y/n): " -n 1 -r core
    echo
    read -p "是否安装开发文档? (y/n): " -n 1 -r docs
    echo
    read -p "是否配置环境变量? (y/n): " -n 1 -r env
    INSTALL_CORE=${core:-n}
    INSTALL_DOCS=${docs:-n}
    SETUP_ENV=${env:-n}
}
# 主安装流程
main_install() {
    local steps=4
    local current=0
    # 收集安装选项
    install_options
    # 步骤1: 检查系统
    current=$((current+1))
    log_info "步骤 $current/$steps: 检查系统... "
    sleep 1
    show_progress $current $steps
    # 步骤2: 复制文件
    current=$((current+1))
    log_info "步骤 $current/$steps: 复制文件... "
    sleep 1
    show_progress $current $steps
    # 步骤3: 配置环境
    current=$((current+1))
    log_info "步骤 $current/$steps: 配置环境... "
    sleep 1
    show_progress $current $steps
    # 步骤4: 完成
    current=$((current+1))
    log_info "步骤 $current/$steps: 完成... "
    sleep 1
    show_progress $current $steps
    log_success "安装完成!"
}
# 执行安装
main_install

Python 安装器(跨平台)

#!/usr/bin/env python3
# ============================================
# Python 简易安装器
# ============================================
import os
import sys
import shutil
import subprocess
import logging
from pathlib import Path
import argparse
# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
class Installer:
    def __init__(self):
        self.install_dir = Path('/usr/local/bin')
        self.config_dir = Path('/etc')
        self.temp_dir = Path('/tmp/installer')
        self.script_name = 'my_script'
    def check_os(self):
        """检查操作系统"""
        if sys.platform == 'darwin':
            logger.info(f'检测到 macOS 系统')
        elif sys.platform == 'linux':
            logger.info(f'检测到 Linux 系统')
        elif sys.platform == 'win32':
            logger.info(f'检测到 Windows 系统')
            self.install_dir = Path(os.environ.get('APPDATA', '/tmp')) / 'my_script'
        else:
            logger.warning(f'未知操作系统: {sys.platform}')
    def check_dependencies(self):
        """检查依赖"""
        requirements = []
        # 检查Python模块
        try:
            import requests
        except ImportError:
            requirements.append('requests')
        try:
            import yaml
        except ImportError:
            requirements.append('pyyaml')
        if requirements:
            logger.info(f'需要安装的依赖: {", ".join(requirements)}')
            if self.confirm('是否需要安装依赖?'):
                self.install_dependencies(requirements)
    def install_dependencies(self, packages):
        """安装依赖"""
        try:
            subprocess.check_call(
                [sys.executable, '-m', 'pip', 'install', *packages]
            )
            logger.info('依赖安装成功')
        except subprocess.CalledProcessError:
            logger.error('依赖安装失败')
            sys.exit(1)
    def create_temp_dir(self):
        """创建临时目录"""
        self.temp_dir.mkdir(parents=True, exist_ok=True)
        logger.debug(f'创建临时目录: {self.temp_dir}')
    def download_files(self):
        """下载文件(示例)"""
        try:
            import requests
            url = 'https://example.com/scripts/my_script.sh'
            response = requests.get(url)
            # 保存到临时目录
            with open(self.temp_dir / self.script_name, 'wb') as f:
                f.write(response.content)
            logger.info(f'成功下载脚本到 {self.temp_dir}')
        except ImportError:
            # 如果没有requests,使用urllib
            import urllib.request
            url = 'https://example.com/scripts/my_script.sh'
            urllib.request.urlretrieve(url, self.temp_dir / self.script_name)
            logger.info(f'成功下载脚本到 {self.temp_dir}')
        except Exception as e:
            logger.error(f'下载失败: {e}')
            sys.exit(1)
    def install_files(self):
        """安装文件"""
        logger.info(f'创建安装目录: {self.install_dir}')
        self.install_dir.mkdir(parents=True, exist_ok=True)
        # 复制文件
        source = self.temp_dir / self.script_name
        target = self.install_dir / self.script_name
        if source.exists():
            shutil.copy2(source, target)
            # 设置执行权限
            target.chmod(0o755)
            logger.info(f'文件已复制到: {target}')
        else:
            logger.error(f'源文件不存在: {source}')
            sys.exit(1)
    def create_config(self):
        """创建配置文件"""
        config_data = f"""
# 配置文件
[installer]
version = "1.0.0"
install_date = "{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
install_dir = "{self.install_dir}"
[database]
host = "localhost"
port = 3306
database = "my_app"
"""
        config_path = self.config_dir / 'my_script.conf'
        with open(config_path, 'w') as f:
            f.write(config_data)
        logger.info(f'配置文件已创建: {config_path}')
    def setup_environment(self):
        """设置环境变量"""
        # 添加到PATH
        export_line = f'export PATH="{self.install_dir}:$PATH"'
        # 检查并添加到bashrc/zshrc
        shell_rc = Path.home() / '.bashrc'
        if sys.platform == 'darwin':
            shell_rc = Path.home() / '.zshrc'
        if export_line not in shell_rc.read_text():
            with open(shell_rc, 'a') as f:
                f.write(f'\n# Added by my_script installer\nexport PATH="{self.install_dir}:$PATH"\n')
            logger.info(f'已将 {self.install_dir} 添加到 PATH')
    def cleanup(self):
        """清理临时文件"""
        if self.temp_dir.exists():
            shutil.rmtree(self.temp_dir)
            logger.debug(f'已清理临时目录: {self.temp_dir}')
    def confirm(self, message):
        """确认询问"""
        response = input(f'{message} [y/n]: ').lower()
        return response in ['y', 'yes']
    def uninstall(self):
        """卸载程序"""
        logger.info('开始卸载...')
        # 删除主程序
        target = self.install_dir / self.script_name
        if target.exists():
            target.unlink()
            logger.info(f'已删除: {target}')
        # 删除配置
        config_path = self.config_dir / 'my_script.conf'
        if config_path.exists():
            config_path.unlink()
            logger.info(f'已删除: {config_path}')
        logger.info('卸载完成')
    def run(self, uninstall_mode=False):
        """主运行函数"""
        if uninstall_mode:
            self.uninstall()
            return
        logger.info("========== 开始安装 ==========")
        # 执行安装步骤
        self.check_os()
        self.check_dependencies()
        self.create_temp_dir()
        self.download_files()
        self.install_files()
        self.create_config()
        self.setup_environment()
        self.cleanup()
        logger.info("========== 安装成功 ==========")
        logger.info(f'可使用命令: {self.script_name}')
        logger.info(f'配置文件: {self.config_dir / "my_script.conf"}')
# 命令行入口
def main():
    parser = argparse.ArgumentParser(description='简易脚本安装器')
    parser.add_argument('-u', '--uninstall', action='store_true', help='卸载程序')
    args = parser.parse_args()
    installer = Installer()
    installer.run(uninstall_mode=args.uninstall)
if __name__ == '__main__':
    main()

自定义安装目录版本

#!/bin/bash
# ============================================
# 自定义安装目录的安装器
# ============================================
VERSION="1.0.0"
DEFAULT_INSTALL_DIR="/usr/local/bin"
# 显示安装信息
show_banner() {
    cat << "EOF"
    ========================================
    简易脚本安装器 v1.0.0
    适用于 Linux/macOS
    ========================================
EOF
}
# 选择安装目录
choose_install_dir() {
    echo "请选择安装目录:"
    echo "1) 保存为默认: $DEFAULT_INSTALL_DIR"
    echo "2) 自定义目录"
    echo "3) 手动输入"
    read -p "请选择 [1-3]: " choice
    case $choice in
        1)
            INSTALL_DIR=$DEFAULT_INSTALL_DIR
            ;;
        2)
            INSTALL_DIR="$HOME/.local/bin"
            mkdir -p "$INSTALL_DIR"
            ;;
        3)
            read -p "请输入安装目录: " INSTALL_DIR
            ;;
        *)
            echo "无效选择,使用默认目录"
            INSTALL_DIR=$DEFAULT_INSTALL_DIR
            ;;
    esac
    echo "安装目录: $INSTALL_DIR"
}
# 备份现有文件
backup_existing() {
    local file="$INSTALL_DIR/$SCRIPT_NAME"
    if [ -f "$file" ]; then
        echo "发现已有文件,进行备份..."
        cp "$file" "$file.bak"
        echo "备份完成: $file.bak"
    fi
}
# 安装与验证
perform_install() {
    # 创建临时文件用于测试
    SCRIPT_NAME="my_app"
    echo "正在创建测试脚本..."
    cat > "/tmp/$SCRIPT_NAME" << 'EOF'
#!/bin/bash
echo "Hello from my script!"
EOF
    # 安装
    install -m 755 "/tmp/$SCRIPT_NAME" "$INSTALL_DIR/$SCRIPT_NAME"
    # 验证
    if [ -x "$INSTALL_DIR/$SCRIPT_NAME" ]; then
        echo "✓ 安装成功: $INSTALL_DIR/$SCRIPT_NAME"
    else
        echo "✗ 安装失败"
    fi
    # 清理
    rm -f "/tmp/$SCRIPT_NAME"
}
# 添加到PATH
add_to_path() {
    case ":$PATH:" in
        *":$INSTALL_DIR:"*)
            echo "该目录已在PATH中"
            ;;
        *)
            echo "export PATH=\"$INSTALL_DIR:\$PATH\"" >> ~/.bashrc
            echo "已添加到 PATH,请重启终端或运行 source ~/.bashrc"
            ;;
    esac
}
# 主流程
main() {
    show_banner
    choose_install_dir
    backup_existing
    perform_install
    add_to_path
    echo
    echo "安装完成!"
    echo "使用: my_app"
}
main "$@"

使用建议

  1. 选择适当的安装位置

    • 系统级 → /usr/local/bin(需要root权限)
    • 用户级 → ~/.local/bin~/.bin(无需root权限)
  2. 安全考虑

    • 验证下载文件的完整性(校验和)
    • 使用可靠的下载源
    • 安装前进行基本的安装检查
  3. 错误处理

    • 捕获所有可能的错误
    • 提供清晰的错误信息
    • 支持回滚机制
  4. 兼容性

    • 检测系统类型
    • 处理不同的包管理器
    • 考虑各种特殊情况
  5. 日志记录

    • 记录安装过程
    • 方便问题排查
    • 支持调试模式

你可以根据实际需要选择适合的版本,并根据具体的安装场景进行适当修改。

抱歉,评论功能暂时关闭!