目录
Toggle运行批量安装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