目录

运行批量安装zabbix_agent的剧本

run.sh
下载
#!/bin/bash

# Zabbix Agent 部署工具
# 支持 CentOS 7/8, Anolis 7/8, Ubuntu 18/22

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 配置
INVENTORY="inventory/hosts.yml"
PLAYBOOK_DIR="."

# 系统类型到 inventory 组的映射
declare -A SYSTEM_GROUPS=(
    ["centos7"]="centos7"
    ["centos8"]="centos8"
    ["anolis7"]="anolis7"
    ["anolis8"]="anolis8"
    ["ubuntu18"]="ubuntu18"
    ["ubuntu22"]="ubuntu22"
)

# 根据现有文件,操作到 playbook 的映射
declare -A ACTION_PLAYBOOKS=(
    ["install"]="install-zabbix-agent.yml"
    ["verify"]="verify-installation.yml"
    ["reinstall"]="reinstall-agent.yml"
    ["test"]="test-install.yml"
    ["step-test"]="step-by-step-test-fixed.yml"
    ["pre-check"]="pre-check.yml"
    ["fix-config"]="fix-centos7-zabbix.yml"
)

# 显示使用说明
show_usage() {
    echo -e "${BLUE}Zabbix Agent 部署工具${NC}"
    echo ""
    echo "使用方法:"
    echo "  $0 <system_type> <action>"
    echo ""
    echo "支持的系统类型:"
    echo -e "  ${GREEN}centos7${NC}   - CentOS 7.x"
    echo -e "  ${GREEN}centos8${NC}   - CentOS 8.x / Rocky Linux 8 / AlmaLinux 8"
    echo -e "  ${GREEN}anolis7${NC}   - Anolis OS 7.x"
    echo -e "  ${GREEN}anolis8${NC}   - Anolis OS 8.x"
    echo -e "  ${GREEN}ubuntu18${NC}  - Ubuntu 18.04 LTS"
    echo -e "  ${GREEN}ubuntu22${NC}  - Ubuntu 22.04 LTS"
    echo ""
    echo "支持的操作:"
    echo -e "  ${GREEN}install${NC}       - 安装 Zabbix Agent"
    echo -e "  ${GREEN}verify${NC}        - 验证 Agent 安装状态"
    echo -e "  ${GREEN}reinstall${NC}     - 重新安装 Agent"
    echo -e "  ${GREEN}test${NC}          - 测试安装"
    echo -e "  ${GREEN}step-test${NC}     - 分步测试"
    echo -e "  ${GREEN}pre-check${NC}     - 安装前检查"
    echo -e "  ${GREEN}fix-config${NC}    - 安装pcre2依赖(仅限centos7)"
    echo ""
    echo "特殊操作:"
    echo -e "  ${GREEN}all <action>${NC}  - 在所有主机上执行操作"
    echo -e "  ${GREEN}list-hosts${NC}    - 列出所有主机"
    echo ""
    echo "示例:"
    echo "  $0 centos7 install      # 在 CentOS 7 主机上安装"
    echo "  $0 anolis8 verify       # 验证 Anolis 8 主机上的 Agent"
    echo "  $0 centos7 fix-config  # 修复 centos7 上的配置"
    echo "  $0 all install          # 在所有主机上安装"
}

# 检查 inventory 文件
check_inventory() {
    if [ ! -f "$INVENTORY" ]; then
        echo -e "${RED}错误: inventory 文件不存在: $INVENTORY${NC}"
        echo "请确保 inventory/hosts.yml 文件存在"
        exit 1
    fi
}

# 检查 playbook 文件
check_playbook() {
    local playbook="$1"
    if [ ! -f "$PLAYBOOK_DIR/$playbook" ]; then
        echo -e "${RED}错误: playbook 文件不存在: $PLAYBOOK_DIR/$playbook${NC}"
        echo "可用的 playbook 文件:"
        ls -la *.yml
        exit 1
    fi
}

# 验证系统类型
validate_system_type() {
    local system_type="$1"
    if [[ ! " ${!SYSTEM_GROUPS[@]} " =~ " $system_type " ]]; then
        echo -e "${RED}错误: 不支持的系统类型 '$system_type'${NC}"
        echo "支持的系统类型: ${!SYSTEM_GROUPS[@]}"
        echo ""
        show_usage
        exit 1
    fi
}

# 验证操作类型
validate_action() {
    local action="$1"
    if [[ ! " ${!ACTION_PLAYBOOKS[@]} " =~ " $action " ]]; then
        echo -e "${RED}错误: 不支持的操作 '$action'${NC}"
        echo "支持的操作: ${!ACTION_PLAYBOOKS[@]}"
        echo ""
        show_usage
        exit 1
    fi
}

# 检查组是否存在
check_group_exists() {
    local group="$1"
    if ! ansible-inventory -i "$INVENTORY" --list | grep -q "\"$group\""; then
        echo -e "${YELLOW}警告: inventory 中未找到组 '$group'${NC}"
        echo "请检查 inventory/hosts.yml 文件中是否定义了该组"
        return 1
    fi
    return 0
}

# 列出主机
list_hosts() {
    echo -e "${BLUE}==================== 主机列表 ====================${NC}"

    # 使用 ansible-inventory 获取详细信息
    for system_type in "${!SYSTEM_GROUPS[@]}"; do
        local group="${SYSTEM_GROUPS[$system_type]}"
        echo -e "\n${GREEN}=== $system_type ($group) ===${NC}"

        # 检查组是否存在
        if check_group_exists "$group"; then
            # 获取该组的主机列表
            ansible-inventory -i "$INVENTORY" --list | \
            python3 -c "
import sys, json
data = json.load(sys.stdin)
group = '$group'
if group in data and 'hosts' in data[group]:
    for host in data[group]['hosts']:
        print(f'  📍 {host}')
    print(f'  总计: {len(data[group][\"hosts\"])} 台主机')
else:
    print('  🚫 未找到主机或组不存在')
"
        else
            echo "  🚫 组不存在"
        fi
    done

    echo -e "\n${BLUE}=================================================${NC}"
}

# 运行 ansible playbook
run_playbook() {
    local system_type="$1"
    local action="$2"
    local extra_vars="system_type=$system_type"

    # 验证操作类型
    validate_action "$action"

    # 获取对应的 playbook
    local playbook="${ACTION_PLAYBOOKS[$action]}"

    check_playbook "$playbook"

    local group="${SYSTEM_GROUPS[$system_type]}"

    echo -e "${BLUE}在 ${system_type} 主机上执行 ${action} 操作...${NC}"
    echo "目标组: $group"
    echo "Playbook: $playbook"
    echo ""

    # 检查组是否存在
    if ! check_group_exists "$group"; then
        echo -e "${RED}错误: 无法继续,组 '$group' 不存在${NC}"
        return 1
    fi

    # 根据不同的 playbook 添加不同的参数
    case "$action" in
        "fix-config"|"verify")
            extra_vars="$extra_vars action=$action"
            ;;
    esac

    ansible-playbook -i "$INVENTORY" \
                     --limit "$group" \
                     --extra-vars "$extra_vars" \
                     "$PLAYBOOK_DIR/$playbook"
}

# 在所有主机上执行操作
run_on_all() {
    local action="$1"

    echo -e "${BLUE}在所有主机上执行 ${action} 操作...${NC}"

    # 验证操作类型
    validate_action "$action"

    local playbook="${ACTION_PLAYBOOKS[$action]}"
    check_playbook "$playbook"

    # 根据不同的 playbook 添加不同的参数
    case "$action" in
        "fix-config"|"verify")
            ansible-playbook -i "$INVENTORY" \
                             --extra-vars "action=$action" \
                             "$PLAYBOOK_DIR/$playbook"
            ;;
        *)
            ansible-playbook -i "$INVENTORY" "$PLAYBOOK_DIR/$playbook"
            ;;
    esac
}

# 主函数
main() {
    # 检查参数数量
    if [ $# -eq 0 ]; then
        show_usage
        exit 1
    fi

    # 检查基本文件
    check_inventory

    local system_type="$1"
    local action="$2"

    # 处理特殊命令
    case "$system_type" in
        "help"|"--help"|"-h")
            show_usage
            exit 0
            ;;
        "list-hosts")
            list_hosts
            exit 0
            ;;
        "all")
            if [ -z "$action" ]; then
                echo -e "${RED}错误: 'all' 需要指定操作${NC}"
                show_usage
                exit 1
            fi
            run_on_all "$action"
            exit 0
            ;;
    esac

    # 验证参数
    if [ -z "$action" ]; then
        echo -e "${RED}错误: 缺少操作参数${NC}"
        show_usage
        exit 1
    fi

    # 验证系统类型
    validate_system_type "$system_type"

    # 执行操作
    run_playbook "$system_type" "$action"
}

# 检查是否有 ansible
if ! command -v ansible-playbook &> /dev/null; then
    echo -e "${RED}错误: 未找到 ansible-playbook 命令${NC}"
    echo "请先安装 Ansible"
    exit 1
fi

# 运行主函数
main "$@"

debian系容器内配置lsyncd

debian系容器内配置lsyncd.sh
下载
#创建必要的目录结构和文件
mkdir -p  /etc/nodes/sites-available  
mkdir -p  /etc/nodes/sites-enabled
mkdir -p  /etc/nodes/streams-available
mkdir -p  /etc/nodes/streams-enabled

cat > /etc/nginx/nginx.conf << 'EOF'
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /run/nginx.pid;
events {
    worker_connections 1024;
}
http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
        '$status $body_bytes_sent "$http_referer" '
        '"$http_user_agent" "$http_x_forwarded_for"';
    access_log /var/log/nginx/access.log main;
    sendfile on;
    #tcp_nopush     on;
    keepalive_timeout 65;
    #gzip  on;
    include /etc/nginx/conf.d/*.conf;
    include /etc/nodes/sites-enabled/*;
}
stream {
    include /etc/nodes/streams-enabled/*;
}
EOF

cat > /etc/nginx/conf.d/stub_status_nginx-ui.conf << 'EOF'
# DO NOT EDIT THIS FILE, IT IS AUTO GENERATED BY NGINX-UI
# Nginx stub_status configuration for Nginx-UI
# Modified at 2025-10-29 14:40:46
server {
    listen 51820;
    server_name localhost;
    # Status monitoring interface
    location /stub_status {
        stub_status;
        allow 127.0.0.1;
        deny all;
    }
}
EOF

# 更新包管理器并安装必要的工具
apt-get update
apt-get install -y lsyncd rsync inotify-tools procps

# 检查安装是否成功
lsyncd -version
rsync --version

# 在容器内创建配置目录
mkdir -p /etc/lsyncd
mkdir -p /var/log/lsyncd
mkdir -p /opt/sync-scripts
mkdir -p /etc/nginx/other_nginx_containers

#创建lsyncd配置文件
# 创建主配置文件
cat > /etc/lsyncd/lsyncd.conf.lua << 'EOF'
-- Lsyncd 配置文件
settings {
    logfile = "/var/log/lsyncd/lsyncd.log",
    statusFile = "/var/log/lsyncd/lsyncd.status",
    statusInterval = 1,
    nodaemon = false
}

-- 双向同步配置:/etc/nodes/ ↔ /etc/nginx/other_nginx_containers
sync {
    default.rsync,
    source = "/etc/nodes/",
    target = "/etc/nginx/other_nginx_containers/",
    rsync = {
        archive = true,
        compress = true,
        verbose = true,
        owner = true,
        group = true,
        perms = true,
        _extra = {"--delete"}
    },
    delay = 1
}

sync {
    default.rsync,
    source = "/etc/nginx/other_nginx_containers/", 
    target = "/etc/nodes/",
    rsync = {
        archive = true,
        compress = true,
        verbose = true,
        owner = true,
        group = true,
        perms = true,
        _extra = {"--delete"}
    },
    delay = 1
}
EOF


# 创建启动脚本
cat > /opt/sync-scripts/start-sync.sh << 'EOF'
#!/bin/bash
echo "启动Lsyncd双向同步服务..."

# 检查配置目录是否存在
mkdir -p /etc/nodes/
mkdir -p /etc/nginx/other_nginx_containers

# 停止已运行的lsyncd(使用kill命令)
if ps aux | grep lsyncd | grep -v grep > /dev/null; then
    echo "停止已运行的lsyncd进程..."
    kill $(ps aux | grep lsyncd | grep -v grep | awk '{print $2}') 2>/dev/null
    sleep 2
fi

# 启动lsyncd
lsyncd /etc/lsyncd/lsyncd.conf.lua

# 检查是否启动成功
sleep 3
if ps aux | grep lsyncd | grep -v grep > /dev/null; then
    echo "✅ Lsyncd启动成功"
    echo "监控日志: tail -f /var/log/lsyncd/lsyncd.log"
else
    echo "❌ Lsyncd启动失败"
    # 查看错误日志
    if [ -f "/var/log/lsyncd/lsyncd.log" ]; then
        echo "错误信息:"
        tail -20 /var/log/lsyncd/lsyncd.log
    fi
    exit 1
fi
EOF

# 创建停止脚本

cat > /opt/sync-scripts/stop-sync.sh << 'EOF'
#!/bin/bash
echo "停止Lsyncd同步服务..."

if ps aux | grep lsyncd | grep -v grep > /dev/null; then
    PID=$(ps aux | grep lsyncd | grep -v grep | awk '{print $2}')
    echo "停止lsyncd进程 (PID: $PID)"
    kill $PID 2>/dev/null
    sleep 2
    
    # 检查是否停止成功
    if ps aux | grep lsyncd | grep -v grep > /dev/null; then
        echo "强制杀死进程..."
        kill -9 $PID 2>/dev/null
    else
        echo "✅ Lsyncd已停止"
    fi
else
    echo "✅ Lsyncd未运行"
fi
EOF

# 创建状态检查脚本
cat > /opt/sync-scripts/status-sync.sh << 'EOF'
#!/bin/bash
echo "=== Lsyncd同步状态 ==="

# 检查进程
if ps aux | grep lsyncd | grep -v grep > /dev/null; then
    PID=$(ps aux | grep lsyncd | grep -v grep | awk '{print $2}')
    echo "✅ Lsyncd进程运行中 (PID: $PID)"
else
    echo "❌ Lsyncd进程未运行"
fi

# 检查日志
if [ -f "/var/log/lsyncd/lsyncd.log" ]; then
    echo "📋 最近日志:"
    tail -10 /var/log/lsyncd/lsyncd.log
else
    echo "📋 日志文件不存在"
fi

# 检查同步目录状态
echo ""
echo "=== 目录同步状态 ==="
nodes_count=$(find /etc/nodes/ -type f 2>/dev/null | wc -l)
nginx_count=$(find /etc/nginx/other_nginx_containers/ -type f 2>/dev/null | wc -l)

echo "📁 /etc/nodes/ ($nodes_count files) ↔ /etc/nginx/other_nginx_containers/ ($nginx_count files)"

if [ "$nodes_count" -eq "$nginx_count" ]; then
    echo "✅ 文件数量一致"
else
    echo "⚠️  文件数量不一致"
fi

echo ""
echo "目录内容对比:"
echo "/etc/nodes/:"
ls -la /etc/nodes/ 2>/dev/null || echo "目录为空或不存在"
echo ""
echo "/etc/nginx/other_nginx_containers/:"
ls -la /etc/nginx/other_nginx_containers/ 2>/dev/null || echo "目录为空或不存在"
EOF

# 创建强制同步脚本
cat > /opt/sync-scripts/force-sync.sh << 'EOF'
#!/bin/bash
echo "执行强制同步..."

# 停止lsyncd
if ps aux | grep lsyncd | grep -v grep > /dev/null; then
    kill $(ps aux | grep lsyncd | grep -v grep | awk '{print $2}') 2>/dev/null
    sleep 2
fi

# 确保目录存在
mkdir -p /etc/nodes/
mkdir -p /etc/nginx/other_nginx_containers/

echo "同步 /etc/nodes/ → /etc/nginx/other_nginx_containers/"
rsync -av --delete /etc/nodes/ /etc/nginx/other_nginx_containers/

echo "同步 /etc/nginx/other_nginx_containers/ → /etc/nodes/"
rsync -av --delete /etc/nginx/other_nginx_containers/ /etc/nodes/

# 重新启动lsyncd
lsyncd /etc/lsyncd/lsyncd.conf.lua
echo "强制同步完成"
EOF


# 设置脚本权限
chmod +x /opt/sync-scripts/*.sh

sh -x /opt/sync-scripts/start-sync.sh
sh -x /opt/sync-scripts/force-sync.sh
sh -x /opt/sync-scripts/status-sync.sh



一键安装libre_office及系统字体

安装libre_office.sh
下载
#!/bin/bash

# LibreOffice 完整安装脚本
# 包含主程序安装和字体安装功能

# 脚本配置
RESOURCES_DIR="/data/resources"
LIBREOFFICE_ARCHIVE="$RESOURCES_DIR/LibreOffice_7.6.7.2_Linux_x86-64_rpm.tar.gz"
FONTS_ZIP="$RESOURCES_DIR/fonts.zip"
INSTALL_DIR="/opt"
LOG_FILE="/var/log/libreoffice_install.log"

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 日志函数
log_info() {
    echo -e "${BLUE}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

log_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

log_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

# 检查root权限
check_root() {
    if [[ $EUID -ne 0 ]]; then
        log_error "此脚本需要root权限运行"
        exit 1
    fi
}

# 检查JDK是否安装
check_jdk() {
    log_info "检查JDK是否已安装..."
    
    local java_installed=false
    
    # 检查Java命令是否存在
    if command -v java &> /dev/null; then
        java_version=$(java -version 2>&1 | head -n1 | cut -d'"' -f2)
        log_success "检测到Java已安装,版本: $java_version"
        java_installed=true
    fi
    
    # 检查rpm包中的JDK
    if rpm -qa | grep -E "java-|jdk-" &> /dev/null; then
        log_success "检测到通过rpm安装的JDK"
        java_installed=true
    fi
    
    if [[ $java_installed == false ]]; then
        log_error "未检测到JDK安装,LibreOffice需要Java运行环境"
        log_info "请先安装JDK,然后重新运行此脚本"
        log_info "推荐安装OpenJDK: yum install -y java-11-openjdk"
        exit 1
	
    fi
}

# 安装系统依赖
install_dependencies() {
    log_info "安装系统依赖包..."
    
    # 安装必要的依赖包
    yum -y install ibus >> "$LOG_FILE" 2>&1
    yum -y install libX11-devel --nogpg >> "$LOG_FILE" 2>&1
    
    if [[ $? -eq 0 ]]; then
        log_success "系统依赖安装完成"
    else
        log_warning "系统依赖安装可能存在問題"
    fi
}

# 安装自定义字体
install_and_verify_fonts() {
    local fonts_temp="/tmp/fonts_install"
    local system_fonts_dir="/usr/share/fonts/custom_fonts"
    
    log_info "开始安装自定义字体..."
    
    # 1. 检查字体包是否存在
    if [[ ! -f "$FONTS_ZIP" ]]; then
        log_warning "字体包不存在: $FONTS_ZIP,跳过字体安装"
        return 0
    fi
    
    # 2. 检查文件格式
    if ! file "$FONTS_ZIP" | grep -q "Zip archive"; then
        log_error "文件不是有效的ZIP格式: $FONTS_ZIP"
        return 1
    fi
    
    # 3. 清理并创建临时目录
    rm -rf "$fonts_temp"
    mkdir -p "$fonts_temp"
    
    # 4. 解压字体包
    log_info "解压字体包..."
    if ! unzip -q "$FONTS_ZIP" -d "$fonts_temp"; then
        log_error "字体包解压失败"
        rm -rf "$fonts_temp"
        return 1
    fi
    
    # 5. 查找字体文件
    local font_files=()
    while IFS= read -r -d '' file; do
        font_files+=("$file")
    done < <(find "$fonts_temp" -type f \( -name "*.ttf" -o -name "*.otf" -o -name "*.ttc" -o -name "*.TTF" -o -name "*.OTF" \) -print0)
    
    if [[ ${#font_files[@]} -eq 0 ]]; then
        log_warning "未找到任何字体文件(.ttf/.otf/.ttc),跳过字体安装"
        rm -rf "$fonts_temp"
        return 0
    fi
    
    log_success "找到 ${#font_files[@]} 个字体文件"
    
    # 6. 创建系统字体目录
    mkdir -p "$system_fonts_dir"
    
    # 7. 复制字体文件并设置权限
    log_info "安装字体文件..."
    for font_file in "${font_files[@]}"; do
        local font_name=$(basename "$font_file")
        cp "$font_file" "$system_fonts_dir/"
        chmod 644 "$system_fonts_dir/$font_name"
        log_info "安装字体: $font_name"
    done
    
    # 8. 更新字体缓存
    log_info "更新字体缓存..."
    if command -v fc-cache >/dev/null 2>&1; then
        if fc-cache -fv "$system_fonts_dir" >> "$LOG_FILE" 2>&1; then
            log_success "字体缓存更新成功"
        else
            log_error "字体缓存更新失败"
            rm -rf "$fonts_temp"
            return 1
        fi
    else
        log_warning "未找到fc-cache命令,跳过缓存更新"
    fi
    
    # 9. 验证字体安装
    log_info "验证字体安装..."
    if command -v fc-list >/dev/null 2>&1; then
        local installed_count=$(fc-list | grep -c "$system_fonts_dir")
        log_success "系统已识别 $installed_count 个新字体"
        
        # 显示部分安装的字体
        fc-list | grep "$system_fonts_dir" | head -5 | while read font; do
            log_info "字体示例: $font"
        done
    fi
    
    # 10. 清理临时文件
    rm -rf "$fonts_temp"
    
    log_success "自定义字体安装完成"
    return 0
}

# 安装LibreOffice主程序
install_libreoffice_main() {
    log_info "开始安装LibreOffice主程序..."
    
    # 检查安装包是否存在
    if [[ ! -f "$LIBREOFFICE_ARCHIVE" ]]; then
        log_error "未找到LibreOffice安装包: $LIBREOFFICE_ARCHIVE"
        exit 1
    fi
    
    # 切换到资源目录
    cd "$RESOURCES_DIR"
    
    # 解压安装包
    log_info "解压安装包..."
    if ! tar -zxvf "LibreOffice_7.6.7.2_Linux_x86-64_rpm.tar.gz" >> "$LOG_FILE" 2>&1; then
        log_error "解压安装包失败"
        exit 1
    fi
    
    # 进入RPM包目录
    local rpm_dir="$RESOURCES_DIR/LibreOffice_7.6.7.2_Linux_x86-64_rpm/RPMS"
    if [[ ! -d "$rpm_dir" ]]; then
        log_error "未找到RPM包目录: $rpm_dir"
        exit 1
    fi
    
    log_info "找到RPM包目录: $rpm_dir"
    cd "$rpm_dir"
    
    # 安装RPM包
    log_info "安装RPM包..."
    if yum -y localinstall *.rpm >> "$LOG_FILE" 2>&1; then
        log_success "RPM包安装成功"
    else
        log_error "RPM包安装失败"
        exit 1
    fi
    
    # 创建符号链接
    if [[ ! -f "/usr/local/bin/soffice" ]]; then
        ln -sf /opt/libreoffice7.6/program/soffice /usr/local/bin/soffice
        log_info "创建符号链接: /usr/local/bin/soffice"
    fi
}

# 配置环境变量
setup_environment() {
    log_info "配置环境变量..."
    
    # 添加到/etc/profile
    if ! grep -q "LibreOffice_PATH" /etc/profile; then
        cat >> /etc/profile << EOF

# LibreOffice Configuration
export LibreOffice_PATH=/opt/libreoffice7.6/program
export PATH=\$LibreOffice_PATH:\$PATH
EOF
        log_success "环境变量已添加到/etc/profile"
    fi
    
    # 设置当前环境变量
    export LibreOffice_PATH=/opt/libreoffice7.6/program
    export PATH=$LibreOffice_PATH:$PATH
}

# 测试安装
test_installation() {
    log_info "开始测试安装..."
    
    local test_pass=0
    local test_total=0
    
    # 测试1: 检查soffice命令
    echo "=== 测试1: 检查soffice命令 ==="
    if command -v soffice >/dev/null 2>&1; then
        log_success "soffice命令可用: $(which soffice)"
        ((test_pass++))
    else
        log_error "soffice命令不可用"
    fi
    ((test_total++))
    
    # 测试2: 检查版本信息
    echo "=== 测试2: 检查版本信息 ==="
    if soffice --version >> "$LOG_FILE" 2>&1; then
        local version=$(soffice --version | head -1)
        log_success "版本检查通过: $version"
        ((test_pass++))
    else
        log_error "版本检查失败"
    fi
    ((test_total++))
    
    # 测试3: 测试文档转换
    echo "=== 测试3: 测试文档转换功能 ==="
    local test_file="/tmp/test_install.txt"
    echo "LibreOffice安装测试文档" > "$test_file"
    echo "创建时间: $(date)" >> "$test_file"
    
    if soffice --headless --convert-to pdf --outdir /tmp "$test_file" >> "$LOG_FILE" 2>&1; then
        if [[ -f "/tmp/test_install.pdf" ]]; then
            local pdf_size=$(stat -c%s "/tmp/test_install.pdf")
            log_success "文档转换功能正常 (PDF大小: ${pdf_size}字节)"
            ((test_pass++))
            rm -f "/tmp/test_install.pdf"
        else
            log_error "文档转换失败 - 未生成PDF文件"
        fi
    else
        log_error "文档转换测试执行失败"
    fi
    ((test_total++))
    rm -f "$test_file"
    
    # 测试4: 检查字体
echo "=== 测试4: 检查字体安装 ==="
    if command -v fc-list >/dev/null 2>&1; then
        local font_count=$(fc-list | wc -l)
        # 修正:使用更可靠的方法统计自定义字体
        local custom_font_count=0
        if [[ -d "/usr/share/fonts/custom_fonts" ]]; then
            custom_font_count=$(find /usr/share/fonts/custom_fonts -name "*.ttf" -o -name "*.otf" -o -name "*.ttc" 2>/dev/null | wc -l)
        fi
        
        log_success "系统字体总数: $font_count, 自定义字体: $custom_font_count"
        ((test_pass++))
        
        # 显示前几个自定义字体(如果存在)
        if [[ $custom_font_count -gt 0 ]]; then
            log_info "自定义字体示例:"
            fc-list | grep "/usr/share/fonts/custom_fonts" 2>/dev/null | head -3 | while read font; do
                log_info "  - $font"
            done
        else
            log_info "未安装自定义字体"
        fi
    else
        log_warning "无法检查字体数量 - fc-list命令不可用"
        ((test_pass++))  # 跳过这个测试,不记失败
    fi
    ((test_total++))

    # 输出测试结果
    echo "================================================"
    log_info "测试结果: $test_pass/$test_total 项测试通过"
    
    if [[ $test_pass -eq $test_total ]]; then
        log_success "🎉 LibreOffice安装测试完全通过!"
        return 0
    else
        log_warning "⚠️  LibreOffice安装存在部分问题"
        return 1
    fi
}

# 显示安装信息
show_installation_info() {
    echo
    echo "================================================"
    echo "LibreOffice 安装完成"
    echo "================================================"
    echo "安装目录: /opt/libreoffice7.6"
    echo "程序路径: /opt/libreoffice7.6/program/soffice"
    echo "符号链接: /usr/local/bin/soffice"
    echo "字体目录: /usr/share/fonts/custom_fonts"
    echo "日志文件: $LOG_FILE"
    echo
    echo "使用示例:"
    echo "  soffice --writer          # 启动Writer"
    echo "  soffice --calc            # 启动Calc"
    echo "  soffice --headless --convert-to pdf input.doc  # 文档转换"
    echo
    echo "即将自动进行安装测试..."
    echo "================================================"
    echo
}

# 清理安装文件
cleanup_installation() {
    log_info "清理安装文件..."
    
    # 删除解压的目录
    if [[ -d "$RESOURCES_DIR/LibreOffice_7.6.7.2_Linux_x86-64_rpm" ]]; then
        rm -rf "$RESOURCES_DIR/LibreOffice_7.6.7.2_Linux_x86-64_rpm"
        log_success "清理安装目录完成"
    fi
}

# 主安装函数
main_installation() {
    log_info "开始LibreOffice完整安装流程..."
    
    # 检查root权限
    check_root
    #检查是否存在Jdk
    check_jdk

    # 创建日志目录
    mkdir -p $(dirname "$LOG_FILE")
    
    # 安装系统依赖
    install_dependencies
    
    # 安装LibreOffice主程序
    install_libreoffice_main
    
    # 安装字体
    install_and_verify_fonts
    
    # 配置环境变量
    setup_environment
    
    # 显示安装信息
    show_installation_info

    # 测试安装
    test_installation
    
    # 清理安装文件
    cleanup_installation

    log_success "LibreOffice安装完成!"
}

# 脚本使用说明
usage() {
    echo "用法: $0 [选项]"
    echo "选项:"
    echo "  -h, --help    显示帮助信息"
    echo "  -t, --test    仅测试安装是否成功,不进行安装"
    echo "  -f, --fonts   仅安装字体"
    echo "  -c, --clean   清理安装文件"
    echo
    echo "示例:"
    echo " bash $0             # 完整安装"
    echo " bash $0 --test      # 仅测试"
    echo " bash $0 --fonts     # 仅安装字体"
    echo " bash $0 --clean     # 清理安装文件"
    echo
    echo "文件位置:"
    echo "  资源目录: $RESOURCES_DIR"
    echo "  安装包: $LIBREOFFICE_ARCHIVE"
    echo "  字体包: $FONTS_ZIP"
    echo "  脚本位置: /data/scripts/install_libreoffice.sh"
}

# 清理函数
cleanup_files() {
    log_info "开始清理安装文件..."
    
    if [[ -d "$RESOURCES_DIR/LibreOffice_7.6.7.2_Linux_x86-64_rpm" ]]; then
        rm -rf "$RESOURCES_DIR/LibreOffice_7.6.7.2_Linux_x86-64_rpm"
        log_success "已清理安装目录"
    else
        log_info "未找到需要清理的安装目录"
    fi
}

# 参数处理
case "$1" in
    -h|--help)
        usage
        exit 0
        ;;
    -t|--test)
        log_info "开始测试LibreOffice安装..."
        test_installation
        exit 0
        ;;
    -f|--fonts)
        log_info "开始安装字体..."
        check_root
        install_and_verify_fonts
        test_installation
        exit 0
        ;;
    -c|--clean)
        log_info "开始清理安装文件..."
        check_root
        cleanup_files
        exit 0
        ;;
    "")
        main_installation
        ;;
    *)
        log_error "未知参数: $1"
        usage
        exit 1
        ;;
esac

定时任务每隔30分钟监控docker占用资源

统计docker占用资源.sh
下载
#!/bin/bash

# Docker容器资源统计脚本
# 作者:zp
# 创建时间:$(date +"%Y-%m-%d %H:%M:%S")

# 配置参数
LOG_DIR="/var/log/dockerxunjian_zp"
CURRENT_DATE=$(date +"%Y-%m-%d")
TIMESTAMP=$(date +"%H:%M:%S")
LOG_FILE="${LOG_DIR}/${CURRENT_DATE}_docker_stats.txt"

# 创建日志目录(如果不存在)
mkdir -p "$LOG_DIR"

# 函数:检查Docker是否运行
check_docker() {
    if ! systemctl is-active --quiet docker; then
        echo "错误:Docker服务未运行"
        exit 1
    fi
}

# 函数:生成分隔符
generate_separator() {
    echo ""
    echo "################################################################################"
    echo "#                           第 $1 次巡检 - $TIMESTAMP                            "
    echo "################################################################################"
    echo ""
}

# 函数:获取系统信息
get_system_info() {
    echo "==================== 系统信息 ===================="
    echo "统计时间:$CURRENT_DATE $TIMESTAMP"
    echo "主机名:$(hostname)"
    echo "操作系统:$(cat /etc/os-release | grep "PRETTY_NAME" | cut -d'"' -f2)"
    echo "内核版本:$(uname -r)"
    echo "系统运行时间:$(uptime -p)"
    echo ""
}

# 函数:获取Docker信息
get_docker_info() {
    echo "==================== Docker信息 ===================="
    echo "Docker版本:$(docker --version 2>/dev/null | cut -d' ' -f3 | cut -d',' -f1)"
    echo "容器数量:$(docker ps -q | wc -l) 个运行中"
    echo "总容器数量:$(docker ps -a -q | wc -l) 个(包括停止的)"
    echo ""
}

# 函数:获取系统资源使用情况
get_system_resources() {
    echo "==================== 系统资源使用情况 ===================="
    
    # 内存使用情况
    total_mem=$(free -h | grep Mem | awk '{print $2}')
    used_mem=$(free -h | grep Mem | awk '{print $3}')
    free_mem=$(free -h | grep Mem | awk '{print $4}')
    mem_usage=$(free | grep Mem | awk '{printf "%.2f", $3/$2 * 100}')
    
    echo "内存使用:$used_mem / $total_mem (使用率: ${mem_usage}%)"
    
    # CPU使用情况(1秒内的平均值)
    cpu_usage=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')
    echo "CPU使用率:${cpu_usage}%"
    
    # 磁盘使用情况(根目录)
    disk_usage=$(df -h / | awk 'NR==2 {print $5}')
    disk_total=$(df -h / | awk 'NR==2 {print $2}')
    disk_used=$(df -h / | awk 'NR==2 {print $3}')
    echo "根目录磁盘使用:$disk_used / $disk_total (使用率: $disk_usage)"
    
    echo ""
}

# 函数:获取容器详细资源使用情况
get_container_stats() {
    echo "==================== 容器资源使用详情 ===================="
    
    # 检查是否有运行的容器
    running_containers=$(docker ps -q)
    if [ -z "$running_containers" ]; then
        echo "当前没有运行的容器"
        echo ""
        return
    fi
    
    # 使用docker stats命令获取实时数据(只获取一次)
    echo "容器名称          CPU使用率   内存使用/限制    内存使用率   网络I/O         块设备I/O      容器ID"
    echo "--------------------------------------------------------------------------------------------------------"
    
    docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}\t{{.Container}}" | tail -n +2
    
    echo ""
}

# 函数:获取容器存储使用情况
get_container_storage() {
    echo "==================== 容器存储使用情况 ===================="
    
    # 获取所有容器(包括停止的)
    all_containers=$(docker ps -a --format "{{.Names}}")
    
    if [ -z "$all_containers" ]; then
        echo "没有找到任何容器"
        echo ""
        return
    fi
    
    for container in $all_containers; do
        # 获取容器大小
        container_size=$(docker ps -a --filter "name=$container" --format "{{.Size}}" 2>/dev/null)
        if [ $? -eq 0 ] && [ ! -z "$container_size" ]; then
            # 获取容器状态
            container_status=$(docker inspect --format='{{.State.Status}}' "$container" 2>/dev/null)
            if [ $? -eq 0 ]; then
                echo "容器: $container (状态: $container_status) - 大小: $container_size"
            else
                echo "容器: $container - 大小: $container_size"
            fi
        fi
    done
    
    echo ""
}

# 函数:获取镜像存储情况
get_image_storage() {
    echo "==================== Docker镜像存储情况 ===================="
    
    # 镜像总大小
    image_total_size=$(docker system df -v 2>/dev/null | grep "Images" | awk '{print $4}')
    if [ ! -z "$image_total_size" ]; then
        echo "镜像总占用空间: $image_total_size"
    fi
    
    # 显示前5个最大的镜像
    echo ""
    echo "前5个最大的镜像:"
    docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" | head -6
    echo ""
}

# 函数:获取巡检次数
get_inspection_count() {
    local log_file="$1"
    if [ -f "$log_file" ]; then
        # 统计文件中已有的巡检次数
        count=$(grep -c "第.*次巡检" "$log_file" 2>/dev/null || echo 0)
        echo $((count + 1))
    else
        echo 1
    fi
}

# 主函数
main() {
    # 检查Docker服务状态
    check_docker
    
    # 获取当前巡检次数
    inspection_count=$(get_inspection_count "$LOG_FILE")
    
    # 追加内容到日志文件
    {
        # 如果是第一次巡检,添加文件头
        if [ "$inspection_count" -eq 1 ]; then
            echo "Docker容器资源每日统计报告"
            echo "统计日期:$CURRENT_DATE"
            echo "日志文件:$LOG_FILE"
            echo "巡检频率:每30分钟一次(每日48次)"
            echo "=================================================================================="
            echo ""
        fi
        
        # 生成巡检分隔符
        generate_separator "$inspection_count"
        
        # 获取各项信息
        get_system_info
        get_docker_info
        get_system_resources
        get_container_stats
        get_container_storage
        get_image_storage
        
        echo "本次巡检结束时间:$(date +"%H:%M:%S")"
        
    } >> "$LOG_FILE"
    
    # 设置正确的文件权限
    chmod 644 "$LOG_FILE"
    
    echo "第 $inspection_count 次巡检完成!结果已追加到: $LOG_FILE"
}

# 脚本执行
main "$@"

收集系统或服务软件日志并保存到到/tmp

收集系统或服务软件日志.sh
下载
#!/bin/bash

TARGET_DIR="/tmp/logs_$(date +"%Y%m%d_%H%M%S")"

mkdir -p "$TARGET_DIR"

echo "开始收集系统日志和服务日志..."

# 1. 收集系统日志目录
echo "收集系统日志..."
cp -r /var/log/* "$TARGET_DIR/" 2>/dev/null

# 2. 收集journalctl系统日志
echo "收集journalctl日志..."
journalctl --since="1 week ago" > "$TARGET_DIR/journalctl_full.log"
journalctl -k > "$TARGET_DIR/kernel.log"
journalctl -u docker > "$TARGET_DIR/docker_service.log"

# 3. 收集系统信息
echo "收集系统信息..."
dmesg > "$TARGET_DIR/dmesg.log"
cat /proc/meminfo > "$TARGET_DIR/meminfo.log"
cat /proc/cpuinfo > "$TARGET_DIR/cpuinfo.log"
free -h > "$TARGET_DIR/memory_usage.log"
df -h > "$TARGET_DIR/disk_usage.log"
top -b -n 1 > "$TARGET_DIR/top_snapshot.log"

# 4. 收集服务状态
echo "收集服务状态..."
systemctl status > "$TARGET_DIR/systemd_status.log"
systemctl list-units --failed > "$TARGET_DIR/failed_services.log"
systemctl list-units --all > "$TARGET_DIR/all_services.log"

# 5. 收集Docker相关日志
echo "收集Docker日志..."
docker logs es > "$TARGET_DIR/docker_es.log" 2>/dev/null
docker logs mysql_backup > "$TARGET_DIR/docker_mysql_backup.log" 2>/dev/null
docker logs mysql_backup_2 > "$TARGET_DIR/docker_mysql_backup_2.log" 2>/dev/null
docker logs postgres_backup > "$TARGET_DIR/docker_postgres_backup.log" 2>/dev/null
docker logs minio-backup > "$TARGET_DIR/docker_minio_backup.log" 2>/dev/null
docker logs minio-backup-108 > "$TARGET_DIR/docker_minio_backup_108.log" 2>/dev/null
docker logs influxdb-backup > "$TARGET_DIR/docker_influxdb_backup.log" 2>/dev/null
docker logs es_snapshot_sync > "$TARGET_DIR/docker_es_snapshot_sync.log" 2>/dev/null

docker ps -a > "$TARGET_DIR/docker_ps.log"
docker stats --no-stream > "$TARGET_DIR/docker_stats.log"

# 6. 收集进程信息
echo "收集进程信息..."
ps aux > "$TARGET_DIR/processes.log"
ps aux --sort=-%mem | head -20 > "$TARGET_DIR/top_memory_processes.log"
ps aux --sort=-%cpu | head -20 > "$TARGET_DIR/top_cpu_processes.log"

# 7. 收集网络信息
echo "收集网络信息..."
ss -tulnp > "$TARGET_DIR/network_connections.log"
netstat -s > "$TARGET_DIR/network_stats.log"
ip addr show > "$TARGET_DIR/network_interfaces.log"

# 8. 收集硬件信息
echo "收集硬件信息..."
lscpu > "$TARGET_DIR/cpu_details.log"
lsblk > "$TARGET_DIR/block_devices.log"
lspci > "$TARGET_DIR/pci_devices.log"

# 9. 收集系统配置
echo "收集系统配置..."
sysctl -a > "$TARGET_DIR/sysctl.conf" 2>/dev/null
cat /etc/systemd/system.conf > "$TARGET_DIR/systemd_system.conf" 2>/dev/null
cat /etc/security/limits.conf > "$TARGET_DIR/limits.conf" 2>/dev/null

# 10. 收集内核日志
echo "收集内核日志..."
dmesg -T > "$TARGET_DIR/dmesg_timestamp.log"
cat /var/log/dmesg > "$TARGET_DIR/dmesg_old.log" 2>/dev/null

# 11. 收集Elasticsearch特定日志(从容器内)
echo "收集Elasticsearch详细日志..."
docker exec es cat /usr/share/elasticsearch/logs/gc.log > "$TARGET_DIR/es_gc.log" 2>/dev/null
docker exec es cat /usr/share/elasticsearch/logs/elasticsearch.log > "$TARGET_DIR/es_main.log" 2>/dev/null

# 12. 收集备份应用日志
echo "收集备份应用日志..."
find /data/backup -name "*.log" -exec cp {} "$TARGET_DIR/" \; 2>/dev/null

# 13. 收集Docker容器日志文件
echo "收集Docker容器日志文件..."
find /var/lib/docker/containers -name "*.log" -exec cp {} "$TARGET_DIR/" \; 2>/dev/null

# 14. 创建日志索引文件
echo "创建日志索引..."
ls -la "$TARGET_DIR/" > "$TARGET_DIR/log_index.txt"

echo "========================================"
echo "日志收集完成!"
echo "目标目录: $TARGET_DIR"
echo "收集的日志文件数量: $(ls "$TARGET_DIR" | wc -l)"
echo "总大小: $(du -sh "$TARGET_DIR")"
echo "========================================"

批量导出docker镜像

save_scripts.sh
下载
#!/bin/bash
#desc: 批量导出docker镜像
docker images |awk 'NR>1{print $1":"$2}' >/root/images.txt
for name in `cat /root/images.txt`
do
  name_new=`echo $name |sed -r 's#:|/#_#g' `
  docker save  ${name} -o ${name_new}.tar
done

检查指定域名($1)的https证书过期时间

check_https.sh
下载
#!/bin/bash
#desc 检查指定的域名的https证书是否过期
#1.vars
export LANG=en_US.UTF-8
url=https://$1
warn=3000
#2.curl 获取日期
expire_date_ori=`curl -v $url  |& grep 'expire date' | awk '{print $4,$5,$(NF-1)}'`
expire_date_second=`date -d "${expire_date_ori}"  +%s`
now_date_second=`date  +%s `
#3.计算
days_left=`echo "($expire_date_second - $now_date_second)/60/60/24" |bc`
#4.判断
if [ $days_left -le $warn ];then
  echo "https证书$url,还有$days_left过期,请及时续费"
fi

将项目目录中所有代码整合到一起以便于交给ai分析

get_codes.sh
下载
#!/bin/bash

# 项目目录
code_src_dir=./app-67l8bp1zso3l_app_version-67l8bp1zso3k/
# 输出代码内容文件
code_dest="code_dest.txt"
# 日志文件
LOG_FILE="logs/download.log"

# 创建日志目录(如果不存在)
mkdir -p "$(dirname "$LOG_FILE")"

# 清空代码内容文件
> "$code_dest"

# 记录开始时间
echo "脚本运行开始时间: $(date)" | tee -a "$LOG_FILE"
echo "==========================================" | tee -a "$LOG_FILE"


# 定义一个数组code_src_name保存项目目录中的所有文件名(排除目录本身),占用内存高,必须bashv4.0+
mapfile -t code_src_name < <(find "$code_src_dir" -type f)

# 统计文件数量:数组前加#
file_count=${#code_src_name[@]}
echo "找到 $file_count 个文件" | tee -a "$LOG_FILE"

# 遍历数组处理文件
for file_path in "${code_src_name[@]}"; do
	echo "处理: $file_path" | tee -a "$LOG_FILE"

    # 写入到目标文件
    {
    	echo "========================================"
    	echo "文件名: $file_path"
    	echo "========================================"
    	[[ -r "$file_path" ]] && cat "$file_path" || echo "无法读取文件"
    	echo -e "\n"
    } >> "$code_dest"
done



#另一种常用的读取文件或脚本执行结果中的内容的方法
# 使用 while read 循环 - 更高效且安全,内存占用低,适用于需要处理的文件比较多的情况
# 初始化计数器
#  file_count=0
#  while IFS= read -r -d '' file_path; do
#  #read -d '':读取直到 null 字符,而不是换行符
#     # 检查是否为普通文件且可读
#      if [[ -f "$file_path" && -r "$file_path" ]]; then
#          echo "处理: $file_path" | tee -a "$LOG_FILE"
#          echo "处理文件: $file_path"
#          
#          # 写入文件信息
#          {
#              echo "========================"
#              echo "FILE: $file_path"
#              echo "========================"
#              cat "$file_path"
#              echo -e "\n"
#          } >> "$code_dest"
#          # 成功处理文件,计数器加1
#          ((file_count++))
#      else
#          echo "跳过文件(不可读或非普通文件): $file_path" >&2
#      fi
#  done < <(find "$code_src_dir" -type f -print0)
#
## 使用 -print0 处理包含特殊字符的文件名
#find -print0:用 null 字符(\0)分隔文件名,而不是换行符
#echo "完成!结果已保存到 $code_dest;日志文件保存在$LOG_FILE "



# 记录结束时间
echo "==========================================" | tee -a "$LOG_FILE"
echo "脚本运行结束时间: $(date)" | tee -a "$LOG_FILE"
echo "总共处理了 $file_count 个文件" | tee -a "$LOG_FILE"

以百分数显示使用率最高的前几个java线程.

show-busy-java-threads.sh
下载
#!/bin/bash
# @Function
# Find out the highest cpu consumed threads of java, and print the stack of these threads.
#
# @Usage
#   $ ./show-busy-java-threads.sh
#
# @author Jerry Lee

readonly PROG=`basename $0`
readonly -a COMMAND_LINE=("$0" "$@")

usage() {
    cat <<EOF
Usage: ${PROG} [OPTION]...
Find out the highest cpu consumed threads of java, and print the stack of these threads.
Example: ${PROG} -c 10

Options:
    -p, --pid       find out the highest cpu consumed threads from the specifed java process,
                    default from all java process.
    -c, --count     set the thread count to show, default is 5
    -h, --help      display this help and exit
EOF
    exit $1
}

readonly ARGS=`getopt -n "$PROG" -a -o c:p:h -l count:,pid:,help -- "$@"`
[ $? -ne 0 ] && usage 1
eval set -- "${ARGS}"

while true; do
    case "$1" in
    -c|--count)
        count="$2"
        shift 2
        ;;
    -p|--pid)
        pid="$2"
        shift 2
        ;;
    -h|--help)
        usage
        ;;
    --)
        shift
        break
        ;;
    esac
done
count=${count:-5}

redEcho() {
    [ -c /dev/stdout ] && {
        # if stdout is console, turn on color output.
        echo -ne "\033[1;31m"
        echo -n "$@"
        echo -e "\033[0m"
    } || echo "$@"
}

yellowEcho() {
    [ -c /dev/stdout ] && {
        # if stdout is console, turn on color output.
        echo -ne "\033[1;33m"
        echo -n "$@"
        echo -e "\033[0m"
    } || echo "$@"
}

blueEcho() {
    [ -c /dev/stdout ] && {
        # if stdout is console, turn on color output.
        echo -ne "\033[1;36m"
        echo -n "$@"
        echo -e "\033[0m"
    } || echo "$@"
}

# Check the existence of jstack command!
if ! which jstack &> /dev/null; then
    [ -z "$JAVA_HOME" ] && {
        redEcho "Error: jstack not found on PATH!"
        exit 1
    }
    ! [ -f "$JAVA_HOME/bin/jstack" ] && {
        redEcho "Error: jstack not found on PATH and $JAVA_HOME/bin/jstack file does NOT exists!"
        exit 1
    }
    ! [ -x "$JAVA_HOME/bin/jstack" ] && {
        redEcho "Error: jstack not found on PATH and $JAVA_HOME/bin/jstack is NOT executalbe!"
        exit 1
    }
    export PATH="$JAVA_HOME/bin:$PATH"
fi

readonly uuid=`date +%s`_${RANDOM}_$$

cleanupWhenExit() {
    rm /tmp/${uuid}_* &> /dev/null
}
trap "cleanupWhenExit" EXIT

printStackOfThread() {
    local line
    local count=1
    while IFS=" " read -a line ; do
        local pid=${line[0]}
        local threadId=${line[1]}
        local threadId0x=`printf %x ${threadId}`
        local user=${line[2]}
        local pcpu=${line[4]}

        local jstackFile=/tmp/${uuid}_${pid}

        [ ! -f "${jstackFile}" ] && {
            {
                if [ "${user}" == "${USER}" ]; then
                    jstack ${pid} > ${jstackFile}
                else
                    if [ $UID == 0 ]; then
                        sudo -u ${user} jstack ${pid} > ${jstackFile}
                    else
                        redEcho "[$((count++))] Fail to jstack Busy(${pcpu}%) thread(${threadId}/0x${threadId0x}) stack of java process(${pid}) under user(${user})."
                        redEcho "User of java process($user) is not current user($USER), need sudo to run again:"
                        yellowEcho "    sudo ${COMMAND_LINE[@]}"
                        echo
                        continue
                    fi
                fi
            } || {
                redEcho "[$((count++))] Fail to jstack Busy(${pcpu}%) thread(${threadId}/0x${threadId0x}) stack of java process(${pid}) under user(${user})."
                echo
                rm ${jstackFile}
                continue
            }
        }
        blueEcho "[$((count++))] Busy(${pcpu}%) thread(${threadId}/0x${threadId0x}) stack of java process(${pid}) under user(${user}):"
        sed "/nid=0x${threadId0x} /,/^$/p" -n ${jstackFile}
    done
}


ps -Leo pid,lwp,user,comm,pcpu --no-headers | {
    [ -z "${pid}" ] &&
    awk '$4=="java"{print $0}' ||
    awk -v "pid=${pid}" '$1==pid,$4=="java"{print $0}'
} | sort -k5 -r -n | head --lines "${count}" | printStackOfThread

批量下载url地址文件

url_download_scripts_v4.sh
下载
#!/bin/bash

# 定义变量
URL_FILE="files/file.txt"
ENCODED_URL_FILE="files/encoded_urls.txt"
LOG_FILE="logs/download.log"
SUCCESS_FILE="logs/success.log"
FAIL_FILE="logs/fail.log"
DOWNLOAD_DIR="files/downloads"

# 创建下载目录和日志目录
mkdir -p "$DOWNLOAD_DIR"
mkdir -p "$(dirname "$LOG_FILE")"
mkdir -p "$(dirname "$ENCODED_URL_FILE")"

# 初始化计数器
total=0
success=0
fail=0

# 清空日志文件
> "$LOG_FILE"
> "$SUCCESS_FILE"
> "$FAIL_FILE"

# 记录开始时间
echo "下载开始时间: $(date)" | tee -a "$LOG_FILE"
echo "==========================================" | tee -a "$LOG_FILE"

# 第一步:对URL文件进行编码处理
echo "正在对URL进行编码处理..." | tee -a "$LOG_FILE"
> "$ENCODED_URL_FILE"

while IFS= read -r url || [[ -n "$url" ]]; do
    # 跳过空行
    url=$(echo "$url" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
    if [[ -z "$url" ]]; then
        continue
    fi
    
    # 对URL进行编码:空格 -> %20, ( -> %28, ) -> %29
    encoded_url=$(echo "$url" | sed '
        s/ /%20/g;
        s/(/%28/g;
        s/)/%29/g
    ')
    
    echo "$encoded_url" >> "$ENCODED_URL_FILE"
    echo "原始: $url" | tee -a "$LOG_FILE"
    echo "编码: $encoded_url" | tee -a "$LOG_FILE"
    echo "---" | tee -a "$LOG_FILE"
    
done < "$URL_FILE"

echo "URL编码完成!编码后的URL保存在: $ENCODED_URL_FILE" | tee -a "$LOG_FILE"
echo "==========================================" | tee -a "$LOG_FILE"

# 第二步:使用编码后的URL进行下载
echo "开始下载文件..." | tee -a "$LOG_FILE"

# 创建文件映射记录,避免重复
declare -A downloaded_files

while IFS= read -r encoded_url || [[ -n "$encoded_url" ]]; do
    # 跳过空行
    encoded_url=$(echo "$encoded_url" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
    if [[ -z "$encoded_url" ]]; then
        continue
    fi

    total=$((total + 1))

    # 从编码后的URL中提取文件名(需要先解码文件名部分)
    original_filename=$(echo "$encoded_url" | sed 's|.*/||' | sed '
        s/%20/ /g;
        s/%28/(/g;
        s/%29/)/g
    ')
    
    # 获取文件扩展名
    extension="${original_filename##*.}"
    if [[ "$extension" == "$original_filename" ]]; then
        extension=""
    else
        extension=".$extension"
    fi
    
    # 生成唯一文件名(添加序号前缀)
    base_filename=$(basename "$original_filename" "$extension")
    filename="${total}_${base_filename}${extension}"
    
    # 检查文件名是否已存在,如果存在则添加时间戳
    if [[ -n "${downloaded_files[$filename]}" ]]; then
        timestamp=$(date +%Y%m%d_%H%M%S)
        filename="${total}_${base_filename}_${timestamp}${extension}"
    fi
    
    downloaded_files[$filename]=1

    # 完整的文件路径
    filepath="${DOWNLOAD_DIR}/${filename}"

    echo "正在下载第 $total 个文件: $filename" | tee -a "$LOG_FILE"
    echo "原始文件名: $original_filename" | tee -a "$LOG_FILE"
    echo "编码URL: $(echo "$encoded_url" | cut -c1-80)..." | tee -a "$LOG_FILE"

    # 使用wget下载文件
    if wget --timeout=30 --tries=3 \
            --user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" \
            -O "$filepath" \
            "$encoded_url" 2>> "$LOG_FILE"; then
        
        # 检查文件是否真的下载成功(文件存在且大小大于0)
        if [[ -f "$filepath" ]] && [[ -s "$filepath" ]]; then
            file_size=$(wc -c < "$filepath")
            echo "✓ 成功下载: $filename ($file_size bytes)" | tee -a "$LOG_FILE"
            echo "$encoded_url -> $filepath ($file_size bytes)" >> "$SUCCESS_FILE"
            success=$((success + 1))
            
        else
            echo "✗ 文件为空或损坏: $filename" | tee -a "$LOG_FILE"
            echo "$encoded_url -> 空文件/损坏" >> "$FAIL_FILE"
            rm -f "$filepath" 2>/dev/null
            fail=$((fail + 1))
        fi
    else
        echo "✗ 下载失败: $filename" | tee -a "$LOG_FILE"
        echo "$encoded_url" >> "$FAIL_FILE"
        fail=$((fail + 1))
    fi

    echo "---" | tee -a "$LOG_FILE"
    
    # 添加延迟,避免对服务器造成太大压力
    sleep 1

done < "$ENCODED_URL_FILE"

# 记录结束时间和统计信息
echo "==========================================" | tee -a "$LOG_FILE"
echo "下载结束时间: $(date)" | tee -a "$LOG_FILE"
echo "==========================================" | tee -a "$LOG_FILE"
echo "总文件数: $total" | tee -a "$LOG_FILE"
echo "成功下载: $success" | tee -a "$LOG_FILE"
echo "下载失败: $fail" | tee -a "$LOG_FILE"

# 使用awk计算成功率(避免bc命令不存在)
if [[ $total -gt 0 ]]; then
    success_rate=$(awk "BEGIN {printf \"%.2f%%\", $success * 100 / $total}")
    echo "成功率: ${success_rate}" | tee -a "$LOG_FILE"
else
    echo "成功率: 0%" | tee -a "$LOG_FILE"
fi

# 输出下载目录的内容和实际文件数
actual_files=$(ls -1 "$DOWNLOAD_DIR" 2>/dev/null | wc -l)
echo "实际下载文件数: $actual_files" | tee -a "$LOG_FILE"

echo "==========================================" | tee -a "$LOG_FILE"
echo "下载目录内容:" | tee -a "$LOG_FILE"
ls -la "$DOWNLOAD_DIR/" | head -15 | tee -a "$LOG_FILE"

# 检查重复文件
echo "==========================================" | tee -a "$LOG_FILE"
echo "检查重复文件..." | tee -a "$LOG_FILE"
ls -1 "$DOWNLOAD_DIR/" | sed 's/^[0-9]*_//' | sort | uniq -d | while read duplicate; do
    count=$(ls -1 "$DOWNLOAD_DIR/" | grep "_${duplicate}$" | wc -l)
    echo "重复文件: $duplicate (出现 $count 次)" | tee -a "$LOG_FILE"
done

# 输出日志文件位置
echo "=========================================="
echo "详细日志: $LOG_FILE"
echo "成功下载列表: $SUCCESS_FILE"
echo "失败下载列表: $FAIL_FILE"
echo "编码后的URL文件: $ENCODED_URL_FILE"
echo "文件下载到: $DOWNLOAD_DIR/"
use_rsync.sh
下载
#!/bin/bash
##########################################
# File Name:use_rsync.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:部署rsync脚本
###########################################

#create color func
#颜色函数
function redecho(){
        input="$@"
        echo -e "\E[1;31m${input}\E[0m"
}
function greenecho(){
        input="$@"
        echo -e "\E[1;32m${input}\E[0m"
}
function blueecho(){
        input="$@"
        echo -e "\E[1;36m${input}\E[0m"
}
function yellowecho(){
        input="$@"
        echo -e "\E[1;33m${input}\E[0m"
}

#1.vars


#check user

echo "################################################"
if [ "`whoami`" = "root" ];then
	greenecho "当前为root用户,开始执行脚本"
else
	redecho "请切换root用户执行此脚本"
	exit 0
fi
echo "------------------------------------------------"

#begin server
blueecho "1.检查是否安装rsync软件包: "
if rpm -qa | grep rsync &>/dev/null;then
	greenecho "系统中已有rsync,跳过安装步骤........."
else
	yum install -y rsync &>/dev/null
	if [ $? -ne 0 ];then
		redecho "安装失败,请检查系统网络/yum源" 
		exit 1
	fi
fi
echo "------------------------------------------------"

config_file=/etc/rsyncd.conf
blueecho "2. 书写配置文件:  此处只支持单个模块的配置与配置文件除了模块外的其他项,如果想部署多个模块请修改脚本中66-82行 "
read -p  "请输入接收文件的模块名字: " name
yellowecho "模块名:$name"
read -p  "请输入模块描述: " comment
yellowecho "模块描述: $comment"
read -p  "请输入模块的文件夹位置:" path
yellowecho "模块文件夹位置:$path"

cat > $config_file <<EOF
uid=rsync
gid=rsync
logfile=/var/log/rsyncd.log
auth users=rsync_backup 
secrets file=/etc/rsyncd.password
fake super=yes
use chroot=no
max connections=2000
timeout=600
pid file=/var/run/rsync.pid
lock file=/var/run/rsync.lock
ignore errors=yes
read only=false
list=false
[$name] 
comment=$comment
path=$path
EOF
if [ $? -eq 0 ];then
	greenecho "成功写入配置文件 "
else
	redecho "写入配置失败,请检查"
	exit 2
fi
echo "------------------------------------------------"
#开始执行部署命令
blueecho "创建rsync用户:"
if id rsync  &>/dev/null ;then
	greenecho "已存在rsync用户,跳过创建步骤......"
else
	useradd -s /sbin/nologin -M rsync
	greenecho "已创建rsync用户"
fi
echo "------------------------------------------------"
blueecho "设置自动传输密码文件rsync.client"
password_file=/etc/rsyncd.password
read -p "设置密码文件rsync.client,请直接输入密码 : " password
echo "rsync_backup:$password" > $password_file && chmod 600 $password_file

echo "------------------------------------------------"
blueecho "创建存放备份的目录并设置目录所属主所属组均为rsync用户"
mkdir -p $path  && chown -R rsync:rsync $path &>/dev/null

echo "------------------------------------------------"

if ! systemctl enable --now rsyncd;then
	blueecho "创建systemd文件,存放位置/etc/systemd/system/rsyncd.service"
cat > /etc/systemd/system/rsyncd.service <<EOF
[Unit]
Description=fast remote file copy program daemon
After=network.target

[Service]
Type=forking
ExecStart=/usr/bin/rsync --daemon --config=/etc/rsyncd.conf
ExecReload=/bin/kill -HUP \$MAINPID

[Install]
WantedBy=multi-user.target
EOF
echo "成功创建systemd文件"
fi

echo "------------------------------------------------"
blueecho "启动rsyncd服务"
if systemctl restart rsyncd && systemctl enable --now rsyncd &>/dev/null;then
	greenecho "服务启动成功,已设置开机自启"
else
	redecho "服务启动失败,请检查配置文件/服务管理文件"
	exit 3
fi

echo "------------------------------------------------"
blueecho "防火墙放行873端口,放行rsyncd服务,重启防火墙"
firewall-cmd --permanent --add-port=873/tcp && firewall-cmd --permanent --add-service=rsyncd && firewall-cmd --reload  &>/dev/null


echo "------------------------------------------------"
blueecho "#解除SELinux安全上下文值限制,允许 rsync 完全访问"
semanage fcontext -a -t rsync_data_t "$path(/.*)?"  &&  restorecon -Rv $path &&   setsebool -P rsync_full_access=1 &&  setenforce 1 &>/dev/null


echo "------------------------------------------------"
read -p "请输入密码创建客户端密码文件: " clientpasswd
client_file=/etc/rsync.client
echo "$clientpasswd" $client_file && chmod 600 $client_file  &>/dev/null


echo "------------------------------------------------"
blueecho   "开始本机测试(自己传自己)"
rsync -av /etc/hostname rsync_backup@$HOSTNAME::$name  --password-file=$client_file  &>/dev/null
if [ $? -eq 0 ];then
	greenecho "传输完成,请检查是否传输成功,查看目录:$path"
	ls -l $path
else
	redecho "传输失败,请检查服务状态/配置文件/脚本变量"
	exit 5
fi
sshfenfa.sh
下载
#!/bin/bash
##########################################
# File Name:sshfenfa.sh
# Version:V1.0
# Author:zhangpeng-vxhs888p
# linuxjk.cn
# Desc:
#1. 检查密钥文件是否存在,如果不存在则创建 ~/.ssh/id_rsa
#2. ip列表(变量,文件,数组)分发公钥
#3. for+分发命令
#4. 检查成功,失败
#5. for+批量执行命令
#6. for+ssh命令 hostname -I
###########################################

#颜色函数
function redecho(){
        input="$@"
        echo -e "\E[1;31m${input}\E[0m"
}
function greenecho(){
        input="$@"
        echo -e "\E[1;32m${input}\E[0m"
}
function blueecho(){
        input="$@"
        echo -e "\E[1;36m${input}\E[0m"
}

#1.vars
key_file=/root/.ssh/id_rsa
pub_file=/root/.ssh/id_rsa.pub
ip_file=/server/scripts/ip.txt
ips="`cat $ip_file`"
pass=linuxjk.cn666
#ips="10.0.0.7 10.0.0.8 10.0.0.9"
#2.检查密钥文件是否存在,如果不存在则创建 ~/.ssh/id_rsa
blueecho "检查密钥文件是否存在"
if [ ! -f ${key_file} ];then
	ssh-keygen -f $key_file -P '' &>/dev/null
	if [ $? -eq 0 ];then
		greenecho "成功创建密钥文件 $key_file "
	else
		redecho "创建密钥文件失败,请检查脚本!"
		exit 1
	fi
else
	greenecho "已存在密钥对,跳过此步......"
fi

#3.分发密钥
blueecho "开始分发密钥"
for ip in $ips
do
	#3.1检查ip是否能ping通
	if  ! ping -c 1 -W 1 $ip &>/dev/null ;then
		redecho "$ip 尝试访问失败,请检查脚本或服务器开机状态"
		continue
	fi
	#3.2分发
	sshpass -p$pass ssh-copy-id -i $pub_file -o StrictHostKeyChecking=no "root@$ip" &>/dev/null
	if [ $? -eq 0 ];then
		greenecho "$ip 密钥分发成功"
		#3.2.1.验证连接
		if  ssh -o StrictHostKeyChecking=no $ip hostname -I &>/dev/null ;then
			greenecho "$ip SSH连接验证成功"
		else
			redecho "$ip SSH连接验证失败"
		fi
	else
		redecho "$ip 密钥分发失败"
	fi
done

greenecho "所有操作已完成!"
exit 0
ip.txt
下载
lb01
lb02
web01
web02
web03
web04
nfs01
backup
db01
m01

案例01:每次用户登录后显示系统基本信息

01_check_sys_cat.sh
下载
#!/bin/bash
##########################################
# File Name:01_check_sys_cat.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例01:每次用户登录后显示系统基本信息
###########################################

#1.vars变量
hostname=`hostname`
username=`whoami`
loadavg=`w | awk 'NR==1 {print$(NF-2),$(NF-1),$NF}'`
cpus=`lscpu | grep "CPU(s):" | awk 'NR==1 {print $2}'`
#procs=`top -bn1 | awk 'NR==2 {print $2}'`
procs=`ps -e --no-headers | wc -l`
zombies=`top -bn1 | awk 'NR==2 {print $(NF-1)}'`
#top_mem_processes=$(ps -eo %mem,comm --sort=-%mem | awk 'NR<=11 && NR>1 {print $2}')
#top_mem_processes=`top -bn1 -w 512 -o %MEM | awk 'NR>=8&&NR<13 {print $12}'` 显示内存占用前10但发现有重复值
top_mem_processes=`top -bn1 -w 512 -o %MEM | awk 'NR>=8&&NR<21 {print $12}' | uniq -c | awk '{print $NF}'`  #去重处理,只显示前13个进程中靠前的几个

mem_total=`free -h | awk 'NR==2 {print $2}'`
mem_sy=`free -h | awk 'NR==2 {print $NF}'`
swap_total=`free -h | awk 'NR==3 {print $2}'`
swap_sy=`free -h | awk 'NR==3 {print $NF}'`
ips=`hostname -I`
#实现登录时提示,切换用户不提示:判断两个变量是否存在,存在表示远程登陆,不存在就是切换用户
# 严格判断:只有 SSH 登录且父进程是 sshd 时才输出
if [ -n "$SSH_CLIENT" ] && [ -n "$SSH_TTY" ] && [ "$(ps -o comm= -p $PPID)" = "sshd" ]; then
cat<<EOF
主机名:$hostname
ip地址:$ips
用户名:$username
系统负载:$loadavg
CPU核心总数:$cpus
进程总数:$procs
僵尸进程数量:$zombies
内存大小/内存剩余:$mem_total $mem_sy
swap大小/swap剩余:$swap_total $swap_sy
Top 10 内存占用进程:
$top_mem_processes
EOF
else
   exit 1
fi
weather.sh
下载
#!/bin/bash
#curl -s wttr.in/longfeng?lang=zh | awk 'NR <= 17; END { print lines[40 - 2] } { lines[NR] = $0 }'


function redstrongecho(){
	input="$@"
	echo -e "\E[1;41m${input}\E[0m"
}
function greenstrongecho(){
	input="$@"
	echo -e "\E[1;42m${input}\E[0m"
}
#if [ -n "$SSH_CLIENT" ] && [ -n "$SSH_TTY" ] && [ "$(ps -o comm= -p $PPID)" = "sshd" ]
#then
redstrongecho "今天的天气是:"

curl -s wttr.in/Jiamusi?lang=zh | awk 'NR <= 17; END { print lines[40 - 2] } { lines[NR] = $0 }'
#else
#	exit 1
#fi

案例02:执行脚本时输入用户名判断用户名是否存在

02_check_user_exist.sh
下载
#!/bin/bash
##########################################
# File Name:02check_user_exist.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例02:执行脚本时输入用户名判断用户名是否存在
###############
############################

#1.vars
user=$1
#2.检查参数数量是否不为1,stop and exit
if [ $# -ne 1 ]
then
	echo "参数数量不对,请重新运行脚本!"
	echo "正确格式:sh *.sh username"
	exit 1
fi
#执行命令,下一步根据此处是否执行成功判断输出信息
id ${user} &>/dev/null
#3. id user--check
if [ $? -eq 0 ]
then
	echo "${user} is exist,detailed information:"
	id ${user}
else
	echo "${user} not exist"
fi

案例03:检查ip或域名是否可以访问

03_check_ip_connect.sh
下载
#!/bin/bash
##########################################
# File Name:03_check_ip_connect.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例03:检查ip或域名是否可以访问
###########################################
#1 vars
ip=$1
#2.检查参数数量是否不为1,stop and exit
if [ $# -ne 1 ]
then 
	echo "脚本参数数量不对,请输入1个ip或域名"
        echo "正确格式:sh *.sh ipaddress/domain name"
	exit 1
fi
#3执行命令,下一步根据此处是否执行成功判断输出信息
ping -c1 ${ip}  &>/dev/null
#4 judge $?
if [ $? -eq 0 ]
then
	echo "connected"
else
	echo "please check your net or input"
fi

案例04:shell中的位置变量$n,当n>9时怎么处理?-----${10} ${11}

04_test_arg.sh
下载
#!/bin/bash
##########################################
# File Name:04_test_arg.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例04:shell中的位置变量$n,当n>9时怎么处理?-----${10} ${11}
###########################################
echo $1 $2 $3... $9 ${10} ${11} ${12}

案例05:$#表示运行脚本时输入参数的个数,一般用于与判断结合 (检查输入参数的数量是否正确)

05_test_jing.sh
下载
#!/bin/bash
##########################################
# File Name:05_test_jing.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例05:$#表示运行脚本时输入参数的个数,一般用于与判断结合 (检查输入参数的数量是否正确)
###########################################
echo $1 $2 $3
echo $#

案例06:执行脚本输入1个或多个用户名通过脚本进行输出 (检查这些用户是否存在)

06_check_multi_users.sh
下载
#!/bin/bash
##########################################
# File Name:06_check_multi_users.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例06:执行脚本输入1个或多个用户名通过脚本进行输出 (检查这些用户是否存在)
###########################################
#1.vars
names="$@"

#2.检查脚本参数个数是否为0(输入是否为空),如果输入为空则退出
if [ $# -eq 0 ];then
	echo "please check your input"
	echo "help: sh  $0 user..."
	exit 1
fi

#3.for
for i in ${names}
do
	#用id命令检查用户是否存在
	id ${i} &>/dev/null
if [ $? -eq 0 ]
then
	id ${i}
else
	echo "$i is not exist"
fi
done

案例07:替代rm的回收站脚本

07_rm.sh
下载
#!/bin/bash
##########################################
# File Name:07_rm.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:替代rm的回收站脚本
###########################################

#1. 创建临时目录
tmp_dir=$(mktemp -d -p /tmp rm_sh_XXXXX)
input_dir="$1"  # 直接使用 $1 更简洁

#2. 校验输入非空
if [ -z "$input_dir" ]; then
    echo "错误:未提供目录参数!"
    exit 1
fi

#3. 解析绝对路径(使用 readlink -f 增强兼容性)
jueduipath=$(readlink -f "$input_dir" 2>/dev/null)
if [ $? -ne 0 ] || [ -z "$jueduipath" ]; then
    echo "failed: $input_dir is not exist"
    exit 1
fi

#4. 检查是否为根目录
if [ "$jueduipath" = "/" ]; then
    echo "this is /, stop your rm !"
    exit 1
fi

#5. 移动目标到临时目录
mv -- "$jueduipath" "$tmp_dir"
if [ $? -eq 0 ]; then
    echo "success save to $tmp_dir"
else
    echo "failed"
fi

案例10:通过脚本传参输入任何一个命令并执行,检查这个命令的执行结果是否正确

10_check_cmd.sh
下载
#!/bin/bash
##########################################
# File Name:10_check_cmd.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例10:通过脚本传参输入任何一个命令并执行,检查这个命令的执行结果是否正确
###########################################
#1.vars
cmd="$@"


#2.检查脚本参数个数是否为0(输入是否为空),如果输入为空则退出
if [ $# -eq 0 ]
then
	echo "error!!! please input correct command"
	echo "help: sh $0 cmd"
	exit 1
fi

#3.执行输入的命令,输出定向到空
$cmd &> /dev/null

#4.进行判断上一条命令的返回值,为0则成功
if [ $? -eq 0 ]
then
	echo "${cmd} success!"
else
	echo "${cmd} error!"
fi

案例11:for循环打印下面这一段话中字母数不大于6的单词

I am a teacher welcome to my home thanks everybody yes or no

11_calc_strings.sh
下载
#!/bin/bash
##########################################
# File Name:11_calc_strings.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例11:for循环打印下面这一段话中字母数不大于6的单词
###########################################

#I am a teacher welcome to my home thanks everybody yes or no
#1.vars
strs="I am a teacher welcome to my home thanks everybody yes or no"
num=6
#2.for
for str in $strs
do
	#begin if <= 6 echo $str
	if [ ${#str} -le $num ]
	then
		echo "$str"
	else
	       echo "$str" &>/dev/null	
	fi
done

案例12:书写脚本检查输入的域名(一个或多个)是否可以ping通--通过read命令实现

12_ping_url.sh
下载
#!/bin/bash
##########################################
# File Name:12_ping_url.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例12:书写脚本检查输入的域名(一个或多个)是否可以ping通--通过read命令实现
source /funcs/func_diy.sh
#调用个人函数库
###########################################
#1.vars:
read -t 40 -p "please input domains: " urls
#-t:40s内无输入则退出 -p:打印后面的提示信息
#2.检查变量是否为空
if [ -z $urls ];then
    echo "Help: 请输入1个或多个域名"
fi
#3.for
for i in ${urls}
do
	ping -c1 ${i} &>/dev/null
	if [ $? -eq 0 ]
	then
		redstrongecho "${i} is yes"
	else
		greenstrongecho "${i} is no"
	fi
done

案例13:计算器传入脚本中2个参数,进行计算,输出结果①命令行传参②read传参

13_num_calc.sh
下载
#!/bin/bash
##########################################
# File Name:13_num_calc.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例13:计算器传入脚本中2个参数,进行计算,输出结果  ①命令行传参
###########################################
#1.vars
num1=$1
num2=$2

#2.检查脚本参数个数是否为2,如果不为2则输出帮助信息并退出
if [ $# -ne 2 ]
then
	echo "help: sh $0 num1 num2"
	exit 3
fi
#3.检查输入的是否为数字
expr 1 + $num1 + $num2 &>/dev/null
if [ $? -ge 2 ]
then
	echo "sh $0 num1 num2"
	exit 1
fi
	
#使用awk计算加减乘除
jia=`awk -v n1=$num1 -v n2=$num2 'BEGIN{print n1+n2}'`
jian=`awk -v n1=$num1 -v n2=$num2 'BEGIN{print n1-n2}'`
cheng=`awk -v n1=$num1 -v n2=$num2 'BEGIN{print n1*n2}'`
chu=`awk -v n1=$num1 -v n2=$num2 'BEGIN{print n1/n2}'`
#4.按照两种格式输出运算结果
cat <<EOF
$num1 + $num2 = $jia
$num1 - $num2 = $jian
$num1 * $num2 = $cheng
$num1 / $num2 = $chu
EOF
echo "
$num1 + $num2 = $jia
$num1 - $num2 = $jian
$num1 * $num2 = $cheng
$num1 / $num2 = $chu"

#3.直接计算并输出
echo "$1 + $2=`echo $num1 + $num2 | bc -l`"
echo "$1 - $2=`echo $num1 - $num2 | bc -l`"
echo "$1 * $2=`echo "$num1 * $num2" | bc -l`"
echo "$1 / $2=`echo $num1 / $num2 | bc -l`"

echo "$1 + $2= `awk -v a=$num1 -v b=$num2 'BEGIN{print a+b}'`"
echo "$1 - $2= `awk -v a=$num1 -v b=$num2 'BEGIN{print a-b}'`"
echo "$1 * $2= `awk -v a=$num1 -v b=$num2 'BEGIN{print a*b}'`"
echo "$1 / $2= `awk -v a=$num1 -v b=$num2 'BEGIN{print a/b}'`"
14_num_calc_read.sh
下载
#!/bin/bash
##########################################
# File Name:13_num_calc_read.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例13:计算器传入脚本中2个参数,进行计算,输出结果  ②read传参
###########################################
#1.vars
read -p "please input two parmeters: " num1 num2

#检查脚本输入是否为空,最多有一个为空则退出
if [ -z "$num1" -o -z "$num2" ]
then
	echo "help: sh $0 num1 num2"
	exit 1
fi
#2.检查参数是否为数字
expr 1 + $num1 + $num2 &>/dev/null
if [ $? -gt 1 ]
then
	echo "error, need input two numbers"
	exit 2
fi

#3.进行计算
#使用 bc计算并直接输出结果
echo "$num1 + $num2= `echo $num1+$num2 | bc -l`"
echo "$num1 - $num2= `echo $num1-$num2 | bc -l`"
echo "$num1 * $num2= `echo $num1*$num2 | bc -l`"
echo "$num1 / $num2= `echo $num1/$num2 | bc -l`"
#使用 awk计算并输出
jia=`awk -v a=$num1 -v b=$num2 'BEGIN{ print a+b}'`
jian=`awk -v a=$num1 -v b=$num2 'BEGIN{print a-b}'`
cheng=`awk -v a=$num1 -v b=$num2 'BEGIN{print a*b}'`
chu=`awk -v a=$num1 -v b=$num2 'BEGIN{print a/b}'`
cat <<EOF
$num1 + $num2 = $jia
$num1 - $num2 = $jian
$num1 * $num2 = $cheng
$num1 / $num2 = $chu
EOF


案例17:通过脚本传参方式传输1个参数,判断是否为文 件,是否为目录,是否具有执行权限.(字符串比较)

17_check_file.sh
下载
#!/bin/bash
##########################################
# File Name:17_check_file.sh
# Version:V3.0
# Author:zhangpeng
# Organization:linuxjk.cn
# Desc: 检查是否为文件,是否为目录,是否具有执行权限.增强文件类型检测(支持软链接)
###########################################

# 参数检查
[ $# -ne 1 ] && { echo "用法: sh $0 文件/目录"; exit 1; }

file="$1"

# 存在性检查
[ ! -e "$file" ] && { echo "错误:$file 不存在!"; exit 1; }

# 类型检测(按检测顺序排序)
#如果软连接指向文件/目录,先检测-f/-d会检测软连接指向的那个文件/目录,所以先检测软连接
if [ -L "$file" ]; then
    type="软链接"
   # target=$(readlink -f "$file")
    
    # 检查目标文件权限
    if [ -x "$target" ]; then
        perm="目标文件有执行权限"
    else
        perm="目标文件无执行权限"
    fi
    
elif [ -f "$file" ]; then
    type="普通文件"
    [ -x "$file" ] && perm="有执行权限" || perm="没有执行权限"
    
elif [ -d "$file" ]; then
    type="目录"
    [ -x "$file" ] && perm="有执行权限" || perm="无执行权限"
    
else
    echo "$file 存在,但无法识别类型(可能是设备文件、管道文件等)"
    exit 1
fi

echo "$file 类型:${type},${perm}"
17_check_file_easy.sh
下载
#!/bin/bash
##########################################
# File Name:17_check_file_1.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:检查是否为文件,是否为目录,是否具有执行权限.(简化版)
###########################################

#1.vars
file=$1

#2.检查参数个数是否为1
[ $# -ne 1 ] && {
	echo "help: sh $0 file"
        exit 1
}
#3.-d 检查是否为目录
if [ -d $file ]
then
	echo "$file is dir"
else
	echo "$file is not a dir"
fi

#4.-f 检查是否为文件
if [ -f $file ]
then
	echo "$file is file"
else
	echo "$file is not a file"
fi
#5. -x 检查是否具有执行权限.
if [ -x $file ];then
		echo "$file has +x"
else
		echo "$file has not +x"
fi

#6.-L 检查是否为软连接
if [ -L $file ];then
	echo "$file is a softlink"
else
	echo "$file is not a softlink"
fi

案例18-检查selinux是否关闭脚本,如果没有关闭提示是否要关闭,yes则关闭,其他就不关闭

18_check_selinux.sh
下载
#!/bin/bash
##########################################
# File Name:18_check_selinux.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:检查selinux是否关闭,如果未关闭,提示是否要关闭,yes则关闭,其他就不关闭
###########################################
#1.vars
#/etc/selinux/config中显示的SELINUX=$perm
#getenforce显示的$temp

#2.取出配置文件/命令行中selinx的状态
#awk -F= '/^SELINUX=/ {print $2}' /etc/selinux/config
perm=`sed -nr '/^SELINUX=/p' /etc/selinux/config | awk -F= '{print $NF}'`
temp=`getenforce`
#3.判断字符串是否为空
if [[ -z "$perm"  ||  -z "$temp" ]]
then
	echo "无法获取selinux策略:请检查配置文件:/etc/selinux/config"
	exit 1
fi

#3.判断以上两个字符串是否同时等于disabled→→→selinux彻底关闭
if [[ "$perm" = "disabled" ]] &&  { [[ "$temp" = Disabled ]] ||  [[ "$temp" = Permissive ]] ;}
then
	echo "SELINUX 已经关闭"
	exit 1
else
	 
#4.此时需要用户输入是否要关闭,yes
        read -p "SELINUX未关闭,是否关闭selinux:关闭请输入yes:" input
	if [ "$input" = yes ];then
		sed -i "s#SELINUX=.*#SELINUX=disabled#g" /etc/selinux/config
		setenforce 0
		echo "已关闭selinux,重启生效"
		exit 1
	else
		echo "selinux is $temp"
		exit 1
	fi
fi
18_check_selinux_easy.sh
下载
#!/bin/bash
##########################################
# File Name:18.check_selinux_1.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例18-检查selinux是否关闭脚本,如果没有关闭提示是否要关闭,yes则关闭,其他就不关闭
###########################################
#1.vars
selinux_config=`awk -F= '/^SELINUX=/ {print $2}' /etc/selinux/config`
selinux_cmd=`getenforce`
#2 判断是否关闭
#两个条件同时成立在[]中需要使用-a,[ 条件1 -a 条件2 ]相当于[]&&[]或[[ 条件1 && 条件2 ]]
if [ "$selinux_config" = "disabled" -a "$selinux_cmd" = "Disabled" ]
then
	echo "SELINUX已经关闭"
else
	read -p "是否关闭selinux,请输入yes/no: " xuan
	if [ "$xuan" = "yes" ];then
		sed -i '/^SELINUX=/s#=.*#=disabled#g' /etc/selinux/config
		setenforce 0
		echo "关闭成功!"
	else
		echo "SELINUX 未关闭!"
	fi
fi

案例20: 书写一个脚本通过read读取输入,判断 输入是整数,浮点数(小数),还是字符.

20_check_type.sh
下载
#!/bin/bash
##########################################
# File Name:20_check_type.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例20: 书写一个脚本通过read读取输入,判断输入数据类型(整数/浮点/字符串)
###########################################

#1. 获取输入
read -p "pls input: " input

#2. 检查输入非空
if [ -z "$input" ]; then
    echo "error Help: sh $0 input"
    exit 1
fi

#3. 判断数据类型
if [[ $input =~ ^[+-]?[0-9]+$ ]]; then           # 整数(含正负)
    echo "zhengshu"
elif [[ $input =~ ^[+-]?[0-9]+\.[0-9]+$ ]]; then  # 浮点数(含正负)
    echo "fudian"
elif [[ $input =~ ^[a-zA-Z0-9]+$ ]]; then        # 纯字母数字组合字符串
    echo "str"
else
    echo "unknown data"
fi
exit 0

案例21: 书写服务检查脚本,执行的时候输入服务名字检查是否运 行,检查是否开启自启动.

21_check_service.sh
下载
#!/bin/bash
##########################################
# File Name: 21_check_service.sh
# Version: V1.1
# Author: zhangpeng
# Organization: linuxjk.cn
# Desc: 服务状态检查脚本
##########################################

# 1. 获取服务名称read -r禁用转义符
read -rp "Please input a service name: " service

# 2. 检查输入是否为空
if [ -z "$service" ]; then
    echo "Usage: sh $0 <service_name>"
    exit 1
fi

# 3. 检查服务是否存在--type确保只检查服务文件
# 直接通过 systemctl 查询(无需管道)
#if ! systemctl list-unit-files --type=service "$service.service" &>/dev/null
if ! systemctl list-unit-files --type=service | grep -qw "^$service.service"; then
    echo "Error: Service '$service' does not exist."
    exit 2
fi

# 4. 获取状态信息
run=$(systemctl is-active "$service")
auto=$(systemctl is-enabled "$service")

# 5. 判断逻辑优化
# 修正后的代码片段
#systemctl is-active "$service" &>/dev/null
#if [ $? -eq 0 ];then
#echo "$service is running"
#else
#echo "$service is running"
#fi
#和下面的格式不同效果一样:命令返回值为0则正确输出,不为0进入else,
#把命令放在if后的弊端:类似于expr那种成功的返回值为0或1 的命令不行
if systemctl is-active "$service" &>/dev/null
then
	echo "$service is running"
else
	echo "$service is not runing"
fi

if systemctl is-enabled "$service" &>/dev/null
then
	echo "$service is enabled"
else
	echo "$service is disenabled"
fi













#if [ "$run" = "active" ]; then
#    status1="running"
#else
#    status1="not running"
#fi

#if [ "$auto" = "enabled" ]; then
#    status2="enabled"
#else
#    status2="disabled"
#fi

#if [ "$run" = "active" ] && [ "$auto" = "enabled" ]; then
#    echo "$service is $status1, and $status2"
#elif [ "$run" = "active" ] && [ "$auto" != "enabled" ]; then
#    echo "$service is $status1"
#elif [ "$auto" = "disabled" ] && [ "$run" = "active" ]; then
#    echo "$service is $status2"
#else
#    echo "$service is not running and disabled"
#    exit 3
#fi
#exit 0

案例22:检查磁盘分区的情况

22_check_disk.sh
下载
#!/bin/bash
##########################################
# File Name:22_check_disk.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:检查磁盘分区情况1.有几个分区2.每个分区使用率,超过70%显示磁盘空间不足,没超过显示异常
###########################################
#1.vars
#分区数量
part_cnt=`egrep -v '^$|#|swap' /etc/fstab | wc -l`
#分区名字
part_names=`egrep -v '^$|#|swap' /etc/fstab | awk '{print $2}'`

#2.for 循环依次处理
for part  in $part_names
do
	size=`df -h $part | awk 'NR==2{print $2}'`
	uselv=`df -h $part | awk -F '[ %]+' 'NR==2{print $5}'`
	if [ "$uselv" -le 70 ]  ;then
	echo "$part 磁盘大小:$size,使用率: $uselv%,空间正常"
else
	echo "$part 磁盘大小:$size,使用率: $uselv%,空间不足!!!"
	let i++
	fi
done
echo "磁盘分区数量:$part_cnt"
echo "磁盘分区空间不足分区数量: ${i:-0}"

案例23:书写多分支格式比较大小脚本

23_num_compare.sh
下载
#!/bin/bash
##########################################
# File Name:23_num_compare.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:多分支格式比较两个数字大小
###########################################
#1.vars
read -p "请输入两个数字进行比较大小: " num1 num2
#2.判断输入是否为空
if [ -z $num1 ] || [ -z $num2 ]
then
	echo "Help: sh $0 num1 num2"
	exit 1
fi
#3.判断输入是否为数字
# expr 1 + $num1 + num2 &>/dev/null
#if [ $? -ge 2 ]
#	echo "请输入数字 格式:sh $0 num1 num2"
#	exit 2
#fi
#字符串比较是否为数字(繁琐)
if [[ ! $num1 =~ ^[+-]?[0-9]+(\.[0-9]+)?$ ]] || [[ ! $num2 =~ ^[+-]?[0-9]+(\.[0-9]+)?$ ]]
then
	echo "请输入数字 格式:sh $0 num1 num2"
	exit 2
fi

#4.比较大小
if [ $num1 -gt $num2 ];then
	echo "$num1 > $num2"
elif [ $num1 -lt $num2 ];then
	echo "$num1 < $num2"
else
	echo "$num1 == $num2"
fi

案例24:根据磁盘空间不同使用率设置不同的警告提示

24_check_disk.sh
下载
#!/bin/bash
##########################################
# File Name:22_check_disk.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:检查磁盘分区情况1.有几个分区2.每个分区使用率,根据不同使用率设置不同的警告提示
###########################################
#1.vars
#分区数量
part_cnt=`egrep -v '^$|#|swap' /etc/fstab | wc -l`
#分区名字
part_names=`egrep -v '^$|#|swap' /etc/fstab | awk '{print $2}'`


#2.for 循环依次处理
for part  in $part_names
do
	size=`df -h $part | awk 'NR==2{print $2}'`
	uselv=`df -h $part | awk -F '[ %]+' 'NR==2{print $5}'`
#根据不同使用率设置不同的警告提示
if [ $uselv -ge 60 ] && [ $uselv -le 70 ]
then
	msg="警告"
	let i++
elif [ $uselv -ge 70 ] && [ $uselv -le 80 ];then
	msg="严重"
	let i++	
elif [ $uselv -ge 80 ] && [ $uselv -le 90 ];then
	msg="故障"
	let i++
elif [ $uselv -ge 90 ] && [ $uselv -le 100 ];then
	msg="灾难"
	let i++
else
	msg="磁盘空间充足,利用率为 $uselv"
fi
echo "$part 大小:$size $msg%"

done
echo "磁盘分区数量:$part_cnt"
echo "磁盘空间不足分区数量:${i:-0}"

案例25:输出指定用户信息(用户巡检脚本),未来可以做安全检查

25_check_user.sh
下载
#!/bin/bash
##########################################
# File Name:25_check_user.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:用户巡检脚本,检查用户信息
###########################################

#一次检查一个用户
#1.vars
#read -p "请输入用户名:" user
#2.check -z
#[ -z $user ] && echo "Help: sh $0 username" && exit 1;
#3.check 输入的是否为用户名(用户是否存在)
#id $user &>/dev/null
#if [ $? -ne  0 ]
#then
#	echo "用户不存在"
#	exit 2
#fi
#


#一次检查多个用户
# 提示用户输入用户名(支持多个,空格分隔)
read -p "请输入要检查的用户名(多个用户名用空格分隔):" input_names

# 检查输入是否为空
if [[ -z "$input_names" ]]; then
    echo "错误:未提供任何用户名。" >&2
    exit 1
fi
# 将输入转换为数组(兼容多个空格/制表符分隔)
names=($(echo "$input_names" | tr -s ' '))  # tr -s ' ' 压缩连续空格
#1.vars
names=("$@")  # 声明为数组
# 检查参数数量
if [ $# -eq 0 ]; then
    echo "错误:请提供至少一个用户名作为参数。"
    echo "用法:bash $0 用户名1 用户名2 ..."
    exit 1
fi

for name in "${names[@]}"; do  # 正确遍历数组
    if id "${name}" &>/dev/null; then
        echo "用户 ${name} 存在。"
        # 获取用户信息
        passwd_entry=$(getent passwd "${name}")
        perm=$(awk -F: '{print $NF}' <<<"$passwd_entry")
        [[ "$perm" == "/bin/bash" || "$perm" == "/bin/zsh" ]] && login="可以登录" || login="不可以登录"
        uid=$(id -u "${name}")
        gid=$(id -g "${name}")
        homedir=$(awk -F: '{print $(NF-1)}' <<<"$passwd_entry")
        situation=$(lastlog -u "${name}")

        # 输出用户信息
	echo "正在检查用户:$name"
echo "----------------------------------------"
        cat <<EOF
用户 ${name} 的详细信息:
- 登录权限:${login}
- UID:${uid}
- GID:${gid}
- 家目录:${homedir}
- 最近登录情况:
${situation}
EOF
echo "========================================"
    else
        echo "错误:用户 ${name} 不存在。"
    fi
done

案例26:case语句格式–菜单选择功能

26_taocan.sh
下载
#!/bin/bash
##########################################
# File Name:26_taocan.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例26:case语句格式–菜单选择功能
###########################################
#1.输出信息供用户选择
cat <<EOF
- 1 138套餐) 吃饱套餐
- 2 443套餐) 吃饱喝足套餐
- 3 888套餐) 吃喝拉撒套餐
- 4 1688套餐) 你想干啥就干啥套餐
EOF
read -p "请选择套餐: " taocan
case "$taocan" in
	1)
		echo "in 1"
		;;
	2)echo "in 2" ;;
	3)echo "in 3" ;;
	4)echo "in 4" ;;
	5)echo "in 5" ;;
	*)echo "error pls run again"
esac

案例27:判断用户输入的是yes还是no(选项中| 的使用)

27_yes_no.sh
下载
#!/bin/bash
##########################################
# File Name:27_yes_no.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例27:判断用户输入的是yes还是no(case菜单选项中| 的使用)
###########################################
read -p "please input yes or no: " yesno
case "$yesno" in
#)前可以用|分割多个同义词,结果都指向)后执行的操作
	yes|Yes|y|Y) echo yes;;
	no|n|N|No) echo no;;
	*) echo ???
esac

案例28:函数基本格式及使用

28_test_func.sh
下载
#!/bin/bash
##########################################
# File Name:28_test_func.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例28:函数基本格式及使用
###########################################
function show() {
echo "welcome to oldboy linux lidao996 class"
echo "你的目标:拿下15k offer"
echo "你的目标:拿下100+ shell脚本"
echo "你的目标:书写总共超过5000行脚本。"
return 0
}
show
#这行表示运行上面刚定义的show函数,作用同下面这种
#function main(){
#    show
#}
#main

案例29:函数传参的使用

29_show_test.sh
下载
#!/bin/bash
##########################################
# File Name:29_show_test.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例29:函数传参的使用
###########################################
function show() {
cat <<EOF
show函数的参数个数:$#
show函数的所有参数:$*
$1.com
$1.cn
$1.org
$1.企业
$1.icu
$1.我爱你
EOF
}
show $*
#使用方法:运行脚本时 sh 29_show_test.sh a b c d e
#命令行传参到函数外部show $* 函数内部$n调用此参数
#显示如下:
#show函数的参数个数:5
#show函数的所有参数:a b c d e
#a.com
#a.cn
#a.org
#a.企业
#a.icu
#a.我爱你

案例30:已有脚本函数化:检查ip是否能访问,将每一步设置为一个函数

30_check_ip_func.sh
下载
#!/bin/bash
##########################################
# File Name:10_ping_url.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例30:已有脚本函数化
###########################################


#1.vars:
function input_urls(){
read  -p "please input domains: " urls
}
#2.检查参数是否为空
function check_urls(){

if [ -z "$urls" ];then
	echo "Help: sh $0 ip/domains"
	exit 1
fi
}
#2.执行ping命令并判断返回值检测此域名是否能ping通
function ping_if(){
	ping -c1 ${url} &>/dev/null
	if [ $? -eq 0 ]
	then
		echo "${url} is yes"
	else
		echo "${url} is no"
	fi
}
#3.for
function for_urls(){
for url in ${urls}
do
	ping_if
done
return 0
}

#4.运行上面的函数
function main(){
input_urls
check_urls
for_urls
}
main

案例31:个人颜色函数库搭建,不同显示效果用不同的函数表示

31_color_func.sh
下载
#!/bin/bash
##########################################
# File Name:31_color_func.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例31:个人颜色函数库搭建,不同显示效果用不同的函数表示
###########################################
function redecho(){
	input="$@"
	echo -e "\E[1;31m${input}\E[0m"
}
function greenecho(){
	input="$@"
	echo -e "\E[1;32m${input}\E[0m"
}
function blueecho(){
	input="$@"
	echo -e "\E[1;36m${input}\E[0m"
}
function yellowecho(){
	input="$@"
	echo -e "\E[1;33m${input}\E[0m"
}

function redstrongecho(){
	input="$@"
	echo -e "\E[1;41m${input}\E[0m"
}
function greenstrongecho(){
	input="$@"
	echo -e "\E[1;42m${input}\E[0m"
}

#以下为测试,使用时redecho "内容"
	redecho 1
	greenecho 1
	yellowecho 1
	blueecho 1
	redstrongecho 1
	greenstrongecho 1

案例32:给个人颜色函数库脚本中加入日志方便以后调用

32_func_diy.sh
下载
#!/bin/bash
##########################################
# File Name:/funcs/func_diy.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例32:给个人颜色函数库脚本中加入日志方便以后调用:
###########################################
#1.颜色函数
function redecho(){
        input="$@"
        echo -e "\E[1;31m${input}\E[0m"
}
function greenecho(){
        input="$@"
        echo -e "\E[1;32m${input}\E[0m"
}
function blueecho(){
        input="$@"
        echo -e "\E[1;36m${input}\E[0m"
}
function yellowecho(){
        input="$@"
        echo -e "\E[1;33m${input}\E[0m"
}
function redstrongecho(){
        input="$@"
        echo -e "\E[1;41m${input}\E[0m"
}
function greenstrongecho(){
        input="$@"
        echo -e "\E[1;42m${input}\E[0m"
}
#2.日志函数
function log() {
  log_file=$0.log
  level=$1
  msg=$2
  time=$(date +%F_%T)
  echo "$time [${level}] ${msg}" >> $log_file
}

案例33:检查指定地址的端口是否可以访问

33_check_port.sh
下载
#!/bin/bash
##########################################
# File Name:check_port.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例33:检查指定地址的端口是否可以访问
#use color funcs
source /funcs/func_diy.sh
###########################################
#1.vars
ip=$1
port=$2
#2.检查参数数量是否为2(ip+端口)
#这一步涉及到传参所以需要在主函数里加上$@
num_part(){
if [ $# -ne 2 ];then
redecho "Help: sh $0 IP PORT  "
exit 1
fi
}

#检查nc/telnet命令是否存在,不存在则安装
use_yum(){
if ! which nc &>/dev/null ;then
yum install -y nc &>/dev/null
fi
#yum install -y telnet &>/dev/null
}

#使用ping命令检查到目标ip之间是否通路
use_ping(){
if ! ping -c1 $ip &>/dev/null ;then
	redecho "this ip connect failed!"
	exit 2
fi
}
#检查端口格式(必须为数字)
check_port(){
if [[ ! $port =~ ^[0-9]+$ ]];then
	redecho "port $port is not exist! pls input number(1-65535) "
	exit 3
fi
}
#3.执行nc命令检查端口连接
use_nc(){
if nc -z ${ip} ${port} ;then
	greenecho "success! $ip $port is open"
else
	redecho "failed! $ip $port is closed "
fi
}


function main(){
num_part "$@"
use_yum
use_ping
check_port
use_nc
}
main "$@"

案例34:检查指定web/api是否可以访问

34_check_url.sh
下载
#!/bin/bash
##########################################
# File Name:34_check_url.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例34:检查指定web/api是否可以访问
#color func
source /funcs/func_diy.sh
###########################################
#1.vars
url=$1

#2.检查参数个数是否为1(空也退出)
check_var(){
if [ $# -ne 1 ]
then
	redecho "help: sh $0 xxx.com "
	exit 1
fi
}
#检查系统中是否有curl命令
yum_curl(){
if  ! which curl &>/dev/null ;then
	yum install -y curl &>/dev/null
fi
}

#检查到目标网站之间线路是否通畅
check_net(){
if ! ping -c1 $url &>/dev/null ;then
	echo "net connection failed! or $url is not exist! "
	exit 2
fi
}
#check [[ =~ ]] .com  可以加一步用正则匹配输入的是否为网站(xxx.com等格式)
#使用curl命令检查是否可以访问
check_url(){
if curl -s $url &>/dev/null ;then
	greenecho "$url  can see! "
else
	redecho "$url see failed! "
fi
}
main(){
check_var "$@"
yum_curl
check_net
check_url
}
main "$@"

案例35:检查域名是否过期

35_check_web_date.sh
下载
#!/bin/bash
##########################################
# File Name:35_check_web_date.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例35:检查域名是否过期 
#func
source /funcs/func_diy.sh
###########################################
#1 vars
#url=linuxjk.cn
#用下面的whois命令取出域名过期时间
# whois linuxjk.cn | egrep -i "(expiry date)|(expiration time)" | awk '{print $(NF-1),$NF}'
export LANG=en_US.UTF-8
url="$1"
if [ -z "$url" ]; then
  read -p "请输入域名(如 xxx.com): " url
fi
#2.检查参数是否为空
if [ -z "$url" ];then
	redecho "Help: sh $0 *.com/cn..."
	exit 1
fi
#取出当前的日期和域名过期日期
date_now=$(date "+%F %T")
date_check=$(whois "$url" 2>/dev/null | egrep -i "(expiry date)|(expiration time)" | awk -F'e: ' '{print $NF}')
if [ -z "$date_check" ]; then
  redecho "无法获取域名 $url 的到期时间"
  exit 2
fi
#3.用date +%s -d将两个日期都转化为秒
date_now_second=$(date +%s -d "$date_now")
date_check_second=$(date +%s -d "$date_check")

#4.测试是否成功转化为秒,此处如果有负数或空值说明转化失败
#echo $date_now_second
#echo $date_check_second


#5.用 awk/bc计算两个日期之间的差值(单位秒)
diff_second=$(awk -v a=$date_now_second -v b=$date_check_second 'BEGIN{print b-a}')
#6.差值转化为天
diff_day=$(awk -v a=$diff_second 'BEGIN{print a/60/60/24}')
diff_month=$(awk -v a=$diff_second 'BEGIN{print a/60/60/24/30}')
diff_year=$(awk -v a=$diff_second 'BEGIN{print a/60/60/24/30/12}')
#7.输出信息
#echo "$url have $diff_day day, =$diff_month month, = $diff_year year"
#if [ $diff_day -ge 60 ];then
if (( $(echo "$diff_day >= 60" | bc -l) )); then
	greenecho "域名$url  还有$diff_day 天到期, 还有 $diff_month月到期, 还有$diff_year年到期"
else
	redecho "请及时续费;"
	redecho "域名$url  还有$diff_day 天到期, 还有 $diff_month月到期, 还有$diff_year年到期"
fi

案例36:使用for循环在/oldboy目录下通过随机的10个小写字母加固定字符oldboy批量创建十个html文件

36_random_file.sh
下载
#!/bin/bash
##########################################
# File Name:36_random_file.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例36:使用for循环在/oldboy目录下通过随的10个小写字母加固定字符oldboy批量创建十个html文件
###########################################
#1.vars
fixed=linux
dir=/oldboy/
#检查目录是否为空,为空则创建
if [ ! -d ${dir} ];then
	mkdir -p $dir
fi
#2.run for
for i in {1..10}
do
#利用两种方法取出10个随机小写字母
file=$(mkpasswd-expect -l 10 -d 0 -s 0 -C 0 )
  #file=$(tr -cd 'a-zA-Z0-9' </dev/urandom | head -c10)
  touch ${dir}${file}_${fixed}.html
done

用for循环打印99乘法表

99.sh
下载
#!/bin/bash
##########################################
# File Name:99.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:利用简单的for循环打印九九乘法表
###########################################
#vars
i=1
j=1

for i in {1..9}
do
	for j in {1..9}
	do
		#printf "%d*%d=%-2d " $i $j $((i*j))
		result=`echo -n "$i*$j"|xargs |bc`
		echo -n "$i*$j=$result "
	done
	echo 
done

案例37:输出1到10并计算总和(条件:循环次数等于10)

37_while_for.sh
下载
#!/bin/bash
##########################################
# File Name:37_while_for.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例37:输出1到10并计算总和(条件:循环次数等于10)
###########################################
#vars
i=1
sum=0
#循环执行条件:i<=10,不满足则结束循环
while [ $i -le 10 ]
do
	echo $i
	let sum=sum+i
	let i++  #控制循环次数
done

echo "总和: $sum"

#for i in {1..10}
#do
#echo $i
#done

案例39:生成随机数字(1-100),判断数字是什么

39_guess_number.sh
下载
#!/bin/bash
##########################################
# File Name:39_guess_number.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例39:生成随机数字(1-100),判断数字是什么
###########################################
#vars
correct_answer=$(echo "$RANDOM%100+1" | bc)
guess=0
#可以用while后面的条件控制循环,当满足猜的数不等于正确答案时进行循环
#while [ $guess -ne $correct_answer ];
#或者用下面的死循环表示,while true,但是当猜的数等于正确答案时输出信息并退出脚本
while true
do
	#read
	read -p "pls input a number: " guess
	#check input ? number
	if  [[ ! $guess =~ [0-9]+ ]];then
		echo "please input number! "
		#continue只跳过这一次输入错误的情况,重新输入,break退出循环,exit退出脚本
		continue
	fi
	let i++
	if [ $guess -lt $correct_answer ];then
		echo "your number is small "
	elif [ $guess -gt $correct_answer ];then
		echo "your number is big "
	else
		echo "correct !!! answer is $correct_answer"
		echo "total guess $i times"
		#下面的exit退出脚本可以改为在这里用break退出循环,下面的判断和输出放在循环外执行
	if [ $i -ge 1 ] && [ $i -le 3 ] ;then	
		echo "better than 99.99% person "
	elif [ $i -ge 4 ] && [ $i -le 6 ];then
		echo "better than 80% person "
	else 
		echo "better than 70% person "
	fi
	exit
	fi	
done

案例40:通过while read方式统计ip.txt文件,并ping文件中的ip(以后ping改成firewalld屏蔽)

40_while_ip_ping.sh
下载
#!/bin/bash
##########################################
# File Name:40_while_ip_ping.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例40:通过while read方式统计ip.txt文件,并ping文件中的ip(以后ping改成firewalld屏蔽)
#funcs
source /funcs/func_diy.sh
###########################################
#vars
src_file=/oldboy/files/ip.txt
#while
while read line
do
	ip=`echo $line | awk -F' ' '{print $1}'`
	num=`echo $line | awk -F' ' '{print $2}'`
       if [ $num -ge 5 ];then
	       ping -c1 $ip &>/dev/null
	       if [ $? -eq 0 ];then
		       greenecho "ping $ip successed"
	       else
		       redecho "ping $ip failed"
	       fi
       fi 

done <$src_file
#while read ip num  只有空格分隔的两列可以这样只定义两个变量,如本案例中的ip 次数
#do
#       #echo "ip address: $ip"
#       if [ $num -ge 8 ];then
#	       ping -c1 $ip &>/dev/null
#       fi 
#done <$src_file

案例41:了解方法2和方法3区别:在while前读取命令和在done后用重定向符<读取文件

41_test_while_read.sh
下载
#!/bin/bash
##########################################
# File Name:41_test_while_read.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:了解方法2和方法3区别:在while前读取命令和在done后用重定向符<读取文件
###########################################
#vars
file=/oldboy/files/ip.txt

i=0
j=0
#方法2,利用管道传递,while处理管道内容,循环次数为0
echo "method 2: while + cat"
cat $file | while read ip 
do
	echo $ip
	let i++
done
echo "times: $i"


#方法3,用输入重定向<输入至while中,循环次数为文件行数
echo "method 3: while + <"
while read ipaddr
do
       echo $ipaddr
       let j++
done <$file
echo "times: $j"

案例41:for/while/ until三种循环格式区别及循环条件分析

41_do_until.sh
下载
#!/bin/bash
##########################################
# File Name:do_until.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例41:for/while/ until三种循环格式区别及循环条件分析
###########################################
#vars

echo "until"
#直到变量i大于10时停止,输出1-10
i=1
until [ $i -gt 10 ]
do
	echo $i
	let i++
done
echo "while"
#满足变量j小于等于10的条件时循环,输出1-10
j=1
while [ $j -le 10 ]
do
	echo $j
	let j++
done
echo "for"
#变量m在1-10的范围内进行循环,输出1-10
for m in {1..10}
do
	echo $m
done

案例42:测试read命令赋值数组并输出数组中的内容

42_read_create_array.sh
下载
#!/bin/bash
##########################################
# File Name:42_read_create_array.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例42:测试read赋值数组并输出数组中的内容
###########################################
#定义数组变量
read -p "请输入数组,空格分隔: " -a array
#测试刚才输入的数组是否可以正常输出
echo ${array[@]}
#测试分割情况(是否一次输出一个)
for i in  ${array[@]}
do
	echo $i
done

案例43:试编写一个shell计算器,求出用户输入所有数字的以下计算结果:总和,平均值,最大值,最小值

43_array_calculate.sh
下载
#!/bin/bash
##########################################
# File Name:43_array_calculate.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例43:求出数组中的值的总和,平均值,最大值,最小值
source /funcs/func_diy.sh
###########################################

#1.vars
function input(){
read -p "请输入需要计算的数字,以空格分割,不限制个数:  " -a array
}

#2.检查数组是否为空
function check_z(){
if [ -z $array ];then
	redecho "未获取到内容,请重新输入! "
	exit 1
fi
}

#易错提示:检查输入的数组是否为数字
#(错误,这里的正则匹配会将整个数组合成一个整体的字符串进行正则匹配,
#无法逐个检测数组中的元素是否为数字)
#if [[ ! ${array[@]} =~ ^[+-]?[0-9]+\.?[0-9]+$ ]];then
#	echo "格式错误,请输入数字! "
#	exit 2
#fi

#下面的错误为如果碰到异常数据会直接退出脚本,不会继续运算
#function check_isnumber(){
#for num in "${array[@]}"
#do
#    # 允许整数、小数、负数,排除空值
#    if [[ ! $num =~ ^[+-]?[0-9]+([.][0-9]+)?$ ]] || [[ $num == '.'* ]] || [[ $num == *'.' ]]; then
#        redecho "错误:'$num' 不是有效的数字!"
#        exit 2
#
#    fi
#done
#}

#3.检查数组中的每个值是否为数字,如果有不是数字的进行提示并跳过这一项,继续进行下面的值的计算,
#得到一个过滤异常数据之后的新数组
i=0
#从下标0开始传入数据
function check_isnumber(){
for num in "${array[@]}"
do
	if [[ ! $num =~ ^[+-]?[0-9]+([.][0-9]+)?$ ]] || [[ $num == '.'* ]] || [[ $num == *'.' ]]; then
		redecho "错误!$num 不是有效的数字,此项无法参与运算"
		continue
	else
		newarray[i]=$num
		let i++
	fi
done
}
echo ${newarray[@]}
#4.开始计算
function  calculate(){
total=$(echo ${newarray[@]} | tr -s ' ' '+' |bc -l)
averavg=$(awk -v a=${total} -v b=${#newarray[@]} 'BEGIN{print a/b}')
max=$(echo ${newarray[@]} | sed 's# #\n#g' | sort -rn | head -n1)
min=$(echo ${newarray[@]} | sed 's# #\n#g' | sort -n | head -n1)
}

#5.输出结果
function output(){
cat<<EOF
数组中的值的计算结果如下:
总和:$total
平均值:$averavg
最大值:$max
最小值:$min
EOF
}


function main(){
	input "$@"
	check_z
	check_isnumber
	calculate
	output
}
main

案例44:把案例30改为数组形式,从server/files/urls.txt读取内容

44_check_ip_func.sh
下载
#!/bin/bash
##########################################
# File Name:42_check_ip_func.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:案例42:将案例30改为数组形式,从指定文件/server/files/urls.txt读取内容
#cat /server/files/urls.txt
#10.0.0.200
#jd.com
#baidu.com
#taobao.com
#linuxjk.cn
#12306.cn
source /funcs/func_diy.sh
###########################################


#1.vars:
function input_urls(){
urls=(`cat /server/files/urls.txt`)
}
#2.检查参数个数是否为0(是否为空),数组用于检查是否为空时可以和变量用法相同

function check_urls(){

if [ -z $urls ];then
	echo "error"
	exit 1
fi

#if [ ${#urls[@]} -eq 0 ];then
#	echo "Help: 未取出正确的url供本脚本检测,请检查脚本! "
#	exit 1
#fi
}
#2.执行ping命令并判断返回值检测此域名是否能ping通
function ping_if(){
	ping -c1 ${url} &>/dev/null
	if [ $? -eq 0 ]
	then
		greenecho "$url 可以访问"
	else
		redecho "$url 不可以访问"
	fi
}
#3.for
function for_urls(){
for url in ${urls[@]}
do
	ping_if
done
return 0
}

#4.运行上面的函数
function main(){
input_urls
check_urls
for_urls
}
main

案例53:用awk统计ip和每个ip对应的流量,取流量排行前50名进行地址查询和单位换算

53_uniq_ip_times.sh
下载
#!/bin/bash
##########################################
# File Name: 53_uniq_ip_times.sh
# Version:V1.0
# Author:zhangpeng
# 0rganization:linuxjk.cn
# Desc:用awk统计ip和每个ip对应的流量,取流量排行前50名进行地址查询和单位换算
###########################################

#1.vars
file=/server/files/access.log
awk_deal=(`awk '{url[$1]=url[$1]+$10}END{for(n in url)print n,url[n]}' $file | sort -rnk2 | head -50`)
count=0
for i in ${awk_deal[@]}
do
        if (( count % 2 == 0 ));then
                echo -n "ipaddress: $i   "
                echo `curl -s cip.cc/${i} | sed -n '2p'`
                sleep 1.5
        else
                echo -n `awk -v a=$i 'BEGIN{print a/1000/1000}'`
                echo " MB"
        fi
        let count++
done
滚动至顶部