SHELL / 编程开发

几个实用的SHELL小脚本工具

浅时光博客 · 1月2日 · 2024年 1.2w 次已读

Linux自签名证书


脚本功能:

利用cfssl工具生成自签名SSL服务器证书

脚本项目地址:点此查看

脚本流程:

  1. 检查并安装cfssl工具。
  2. 用户输入CA证书的一些配置信息,如证书过期时间、域名、国家、地区等。
  3. 创建CA配置文件(ca-config.json)和CA证书签发请求文件(ca-csr.json)。
  4. 利用cfssl工具生成CA证书(ca.pem)和私钥(ca-key.pem)。
  5. 用户输入服务器证书的配置信息。
  6. 创建服务器证书签发请求文件(<domain>-csr.json)。
  7. 利用cfssl工具生成服务器证书(<domain>.pem)、私钥(<domain>-key.pem)。

脚本内容:

#!/usr/bin/env bash

#===============================================================================
#
#          FILE: Generating_ssl.sh
# 
#         USAGE: bash Generating_ssl.sh
#   DESCRIPTION: 基于cfssl工具实现自签名SSL服务器证书
# 
#  ORGANIZATION: dqzboy.com
#       CREATED: 2022
#===============================================================================


## 安装部署cfssl工具
ADD_CFSSL() {
echo
echo "-------------------------------------<提 示>-------------------------------------"
echo "                           检查服务器是否安装CFSSL工具!"
echo "-------------------------------------< END >-------------------------------------"
echo

cfsslVer="1.6.3"
if [ -f /usr/local/bin/cfssl ];then
    echo "Skip..."
else
    wget https://mirrors.chenby.cn/https://github.com/cloudflare/cfssl/releases/download/v${cfsslVer}/cfssl_${cfsslVer}_linux_amd64
    mv cfssl_${cfsslVer}_linux_amd64 /usr/local/bin/cfssl
fi

if [ -f /usr/local/bin/cfssl-certinfo ];then
    echo "Skip..."
else
    wget https://mirrors.chenby.cn/https://github.com/cloudflare/cfssl/releases/download/v${cfsslVer}/cfssl-certinfo_${cfsslVer}_linux_amd64
    mv cfssl-certinfo_${cfsslVer}_linux_amd64 /usr/local/bin/cfssl-certinfo
fi

if [ -f /usr/local/bin/cfssljson ];then
    echo "Skip..."
else
    wget https://mirrors.chenby.cn/https://github.com/cloudflare/cfssl/releases/download/v${cfsslVer}/cfssljson_${cfsslVer}_linux_amd64
    mv cfssljson_${cfsslVer}_linux_amd64 /usr/local/bin/cfssljson
fi
# 赋予执行权限
chmod +x /usr/local/bin/cfssl*


cfssl version
}
## 生成CA证书
CA_NAMES() {
mkdir -p /data/cert && cd /data/cert
echo
echo "-------------------------------------<提 示>-------------------------------------"
echo "                               直接回车,使用默认值!"
echo "-------------------------------------< END >-------------------------------------"
echo
read -p "请输入证书过期时间[8760h(1年|Default)|19800h(825天)|87600h(10年)]:" input
if [ -z "${input}" ];then
    input="16800h"
    echo ${input}
fi
echo "-------------------------------------------------------------------------------------"
read -p "请输入域名[不可缺失!]:" inputURL
if [ -z "${inputURL}" ];then
    echo "参数为空,退出执行"
    exit 1
fi
echo "-------------------------------------------------------------------------------------"
read -p "请输入国家[Default: CN]:" inputC
if [ -z "${inputC}" ];then
    inputC="CN"
    echo ${inputC}
fi
echo "-------------------------------------------------------------------------------------"
read -p "请输入地区、城市[Default: Shanghai]:" inputL
if [ -z "${inputL}" ];then
    inputL="Shanghai"
fi
echo "-------------------------------------------------------------------------------------"
read -p "请输入州、省[Default: Shanghai]:" inputST
if [ -z "${inputST}" ];then
    inpuST="Shanghai"
fi
echo "-------------------------------------------------------------------------------------"
read -p "请输入组织名称,公司名称[Default: DEVOPS]:" inputO
if [ -z "${inputO}" ];then
    inpuO="DEVOPS"
fi
echo "-------------------------------------------------------------------------------------"
read -p "请输入组织单位名称,公司部门[Default: DEVOPS]:" inputOU
if [ -z "${inputOU}" ];then
    inpuOU="DEVOPS"
fi
echo "-------------------------------------------------------------------------------------"
}

CREATE_CA() {
echo "================================================< CA CONFIG >================================================"
cat > ca-config.json <<EOF
{
    "signing": {
        "default": {
            "expiry": "${input}"
        },
        "profiles": {
            "Server": {
                "expiry": "${input}",
                "usages": [
                    "signing",
                    "key encipherment",
                    "server auth"
                ]
            },
            "Client": {
                "expiry": "${input}",
                "usages": [
                    "signing",
                    "key encipherment",
                    "client auth"
                ]
            }
        }
    }
}
EOF

echo "================================================< CA CSR >================================================"
cat > ca-csr.json <<EOF
{
    "CN": "${inputURL}",
    "hosts": [
        "${inputURL}"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "${inputC}",
            "ST": "${inputST}",
            "L": "${inputL}",
            "O": "${inputO}",
            "OU": "${inputOU}"
        }
    ]
}
EOF

echo "==================================================< CA CREATE  >=================================================="
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
echo "================================================< CA CREATE DONE >================================================"

}

CREATE_SERVER() {
mkdir -p /data/cert/${inputURL} && cd /data/cert/${inputURL}
echo "================================================< SERVER CSR >================================================"
cat > ${inputURL}-csr.json <<EOF
{
    "CN": "${inputURL}",
    "hosts": [
        "${inputURL}"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "${inputC}",
            "ST": "${inputST}",
            "L": "${inputL}",
            "O": "${inputO}",
            "OU": "${inputOU}"
        }
    ]
}
EOF

echo "================================================<SERVER SSL CREATE>================================================"
cfssl gencert -ca=/data/cert/ca.pem -ca-key=/data/cert/ca-key.pem -config=/data/cert/ca-config.json -profile=Server ${inputURL}-csr.json | cfssljson -bare ${inputURL}
echo "================================================< SERVER SSL DONE >================================================"
}

main() {
    ADD_CFSSL	
    CA_NAMES
    CREATE_CA
    CREATE_SERVER
}
main

Linux资源使用率


脚本功能:

  • calculate_load.sh:计算当前服务器1分钟、5分原文链接:https://www.dqzboy.com钟、15分钟的负载
  • get_cpu-disk.sh:每隔 5 秒检测一次 CPU、内存和磁盘的占用率,并将检测结果输出到终端。可以根据需要修改脚本中的检测间隔和检测内容
  • get_disk_usage_alert.sh:结合磁盘使用率查询和邮件告警两个功能,用于监控服务器磁盘的空间使用情况
  • get_proc_stat.sh:根据进程名或PID或进程命令行参数查询进程,并输出相关进程信息
  • get_top_proc.sh:输出系统当前占用资源(cpu、内存、IO、流量等等)最多的Top10进程
  • get_top_proc_in_oneline.sh:输出系统当前占用资源(cpu、内存)最多的TopN进程

脚本项目地址:点此查看

脚本内容:

  • calculate_load.sh
#!/usr/bin/env bash
#===============================================================================
#
#          FILE: calculate_load.sh
# 
#         USAGE: ./calculate_load.sh 
# 
#   DESCRIPTION: 计算当前服务器1分钟、5分钟、15分钟的负载
# 
#  ORGANIZATION: dqzboy.com
#===============================================================================

# 获取CPU核心数量
cpu_cores=$(grep -c ^processor /proc/cpuinfo)

# 使用uptime命令获取系统负载平均值
load_averages=$(uptime | awk -F'average:' '{print $2}' | tr -d ',')

# 提取1分钟、5分钟和15分钟的负载值
load_1min=$(echo "$load_averages" | awk '{print $1}')
load_5min=$(echo "$load_averages" | awk '{print $2}')
load_15min=$(echo "$load_averages" | awk '{print $3}')

# 计算load average百分比
load_1min_percentage=$(echo "scale=2; $load_1min / $cpu_cores * 100" | bc)
load_5min_percentage=$(echo "scale=2; $load_5min / $cpu_cores * 100" | bc)
load_15min_percentage=$(echo "scale=2; $load_15min / $cpu_cores * 100" | bc)

calculate_percentage() {
    local load_value=$1
    local percentage=$(echo "scale=2; $load_value / $cpu_cores * 100" | bc)

    # 小于0.01的情况显示为具体值,否则显示两位小数
    if (( $(echo "$percentage < 0.01" | bc -l) )); then
        echo "$percentage"
    else
        echo "$(printf "%.2f" $percentage)"
    fi
}

# 打印结果
echo "CPU Cores: $cpu_cores"
echo "Load Average (1min): $load_1min, Load Percentage: $(calculate_percentage $load_1min)%"
echo "Load Average (5min): $load_5min, Load Percentage: $(calculate_percentage $load_5min)%"
echo "Load Average (15min): $load_15min, Load Percentage: $(calculate_percentage $load_15min)%"
  • get_cpu-disk.sh
#!/usr/bin/env bash
#===============================================================================
#
#          FILE: get_cpu-disk.sh
# 
#         USAGE: ./get_cpu-disk.sh
#         
#       DESCRIPTION: 每隔 5 秒检测一次 CPU、内存和磁盘的占用率,并将检测结果输出到终端。可以根据需要修改脚本中的检测间隔和检测内容
# 
#       ORGANIZATION: dqzboy.com
#===============================================================================

while true
do
  # 获取 CPU 占用率
  cpu_load=$(top -bn1 | grep "Cpu(s)" | awk '{print $2 + $4}')
  cpu_load=${cpu_load/.*}

  # 获取内存占用率
  mem_used=$(free | grep Mem | awk '{print $3/\ * 100.0}')
  mem_used=${mem_used/.*}

  # 获取磁盘占用率
  disk_used=$(df / | awk '/\// {print $5}' | sed 's/%//g')

  # 打印资源使用情况
  echo "CPU 占用率:$cpu_load%"
  echo "内存占用率:$mem_used%"
  echo "磁盘占用率:$disk_used%"

  # 等待 5 秒
  sleep 5
done
  • get_disk_usage_alert.sh
#!/usr/bin/env bash
#===============================================================================
#
#          FILE: get_disk usage_alert.sh
# 
#         USAGE: ./get_disk usage_alert.sh [File_system|Mounted_on]
#                ./get_disk usage_alert.sh [-i|-u]
#   DESCRIPTION: open_mail_alert字段设置为1时:
#				 根据Filesystem(例如:/dev/sda1)或 Mounted on(例如:/data)获取磁盘使用率
#				 并输出Disk usage(例如:15%);如果没有输入参数则输出全部Disk usage,Mounted_on信息
#
#				 open_mail_alert字段设置为0时:
#                监控monitor_mount_dir字段中定义的监控分区,添加到crontab中,当分区超过使用率时,发出邮件告警
#				 (一般使用QQ邮箱需要使用ssl方式发送邮件,163邮件使用普通方式就OK)
# 
#  ORGANIZATION: dqzboy.com
#===============================================================================

ok(){
    echo "$(date +%F\ %T)|$$|$BASH_LINENO|info|job success: $*" 
    exit 0
}

die(){
    echo "$(date +%F\ %T)|$$|$BASH_LINENO|error|job fail: $*" >&2
    exit 1
}

usage() { 
    cat <<_OO_
USAGE:
    $0 [File_system|Mounted_on]

_OO_
}
#邮件告警功能字段定义
open_mail_alert=0 # 0代表关闭邮件告警,开启查询磁盘使用率模式;1代表开启邮件告警,关闭查询磁盘使用率模式;默认为关闭状态,以下邮件信息配置好后方可打开,否则会导致邮件告警失败
mail_from="[email protected]" #定义邮件告警发件人
mail_to="[email protected],[email protected],[email protected]" #定义邮件告警收件人,多个告警收件人用逗号分隔(,)
smtp_addr_port="smtp.qq.com:465" #定义smtp地址和端口,如果不指定端口,默认为25
mail_user="[email protected]" #定义发件人用户
mail_password="xxx" #定义发件人密码
ssl_enable=1 #1代表发送告警邮件使用SSL协议,0代表使用普通邮件协议,默认设置为0
monitor_mount_dir="all" #定义需告警的挂载目录,多个挂载目录用竖线分隔(|),如果要监控服务器上所有磁盘需要输入 ALL
alert_limit=60 #设置告警阈值百分比,如果磁盘空间使用等于或超过设置阈值则发出邮件告警
monitoring_interval=5 #设置监控告警间隔,单位为分钟


#获取磁盘使用率函数
disk_usage_info=""
get_disk_usage(){
    local filesystem_or_mount="$1"
	if [[ -z "$filesystem_or_mount" ]];then
		disk_usage_info=$(df|awk 'NR>1{print $(NF-1),$NF}'|sort -r)
		echo "$disk_usage_info"
	else
		local tmp_filesystem_or_mount=${filesystem_or_mount/\/dev\//}
		local tmp_mount=$(df $tmp_filesystem_or_mount 2>/dev/null|awk 'NR>1{print $(NF-1)}')
		if [[ -z "$tmp_mount" ]];then
			df /dev/$tmp_filesystem_or_mount 2>/dev/null|awk 'NR>1{print $(NF-1)}'
		else
			echo "$tmp_mount"
		fi
	fi
}


if [[ $open_mail_alert -eq 0 ]];then
    #获取磁盘使用率
    disk_usage_result=$( get_disk_usage "$1" )
    if [[ -z "$disk_usage_result" ]];then
    	die "Get disk usage fail,please confirm the $1 file_system or mount_on existence"
    else
    	ok "$disk_usage_result"
    fi
elif [[ $open_mail_alert -eq 1 ]];then
	#安装定期监控
	if [[ $1 == "-i" ]];then
        #如果开启邮件告警功能执行者必须是root权限
	    if ! id | grep -Eq '^uid=0\('; then
	    	die "You must use the root user to open the mail alert"
	    fi
	    
	    #判断mail程序是否存在
	    mail_bin=$( which mailx )
	    if [[ -z "$mail_bin" ]];then
	    	die "You must install the mailx package"
	    fi
		
		#判断smtp服务器是否可以ping通
	    smtp_addr=$( echo "$smtp_addr_port"|awk -F ":" '{print $1}' )
	    ping -c 1 $smtp_addr 1>/dev/null 2>&1
	    if [[ $? -ne 0 ]];then
	    	die "Please check the SMTP address $smtp_addr connectivity"
	    fi
		
		#如果开启了SSL协议
		if [[ $ssl_enable -eq 1 ]];then
			ssl_dir=~/.certs
			smtp_addr_port_ssl="smtps://$smtp_addr_port" #添加ssl协议头
			
			#判断openssl程序是否存在
			ssl_bin=$( which openssl )
			if [[ -z "$ssl_bin" ]];then
				die "You must install the openssl package"
			fi
			
			#生成smtps所需证书
			[[ -d $ssl_dir ]] || mkdir -p $ssl_dir
			[[ -s $$ssl_dir/smtps.crt ]] && rm -f $ssl_dir/smtps.crt
			echo -n | openssl s_client -connect "$smtp_addr_port" 2>/dev/null| sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > $ssl_dir/smtps.crt
			if [[ ! -s $ssl_dir/smtps.crt ]];then
				die "Failed to generate certificate $ssl_dir/smtps.crt"
			fi	
			certutil -A -n "GeoTrust SSL CA" -t "C,," -d ~/.certs -i $ssl_dir/smtps.crt 1>/dev/null 2>&1
			if [[ $? -ne 0 ]];then
				die "Failed to certutil1 certificate $ssl_dir/smtps.crt"
			fi
			certutil -A -n "GeoTrust Global CA" -t "C,," -d ~/.certs -i $ssl_dir/smtps.crt 1>/dev/null 2>&1
			if [[ $? -ne 0 ]];then
				die "Failed to certutil2 certificate $ssl_dir/smtps.crt"
			fi
			certutil -L -d $ssl_dir 1>/dev/null 2>&1
			if [[ $? -ne 0 ]];then
				die "Failed to certutil3 certificate $ssl_dir/smtps.crt"
			fi
		fi
		
		#添加crontab
		cron_file='/var/spool/cron/root'
		sciprt_name=$(cd "$(dirname "$0")";pwd)/$(basename "$0")
		chmod +x $sciprt_name
		echo "*/${monitoring_interval} * * * * $sciprt_name 1>/dev/null 2>&1" >>$cron_file
		service crond reload 1>/dev/null 2>&1
		ok "Install mail monitoring success"
    fi
	
	
	#卸载定期监控
	if [[ $1 == "-u" ]];then
		cron_file='/var/spool/cron/root'
		sciprt_name=$(basename "$0")
		/bin/sed -i '/'${sciprt_name}'/d' $cron_file
		service crond reload 1>/dev/null 2>&1
		ok "Uninstall mail monitoring success"
    fi
	
	
	#执行监控逻辑
    #Get IP ADDRESS	
    ip=$( /sbin/ifconfig|awk -F ":| +" '{if($0 ~ /inet addr:/ && $4 !~ /127\.0\./){print $4}}' )
	
	#如果monitor_mount_dir值为ALL,则监控服务器全部分区
	capital_all=$( echo "$monitor_mount_dir"|tr [a-z] [A-Z] )
	if [[ $capital_all == "ALL" ]];then
		monitor_mount_dir_tmp=$( df|awk 'BEGIN{monitor_list=""}NR>1{monitor_list=monitor_list"|"$NF}END{print monitor_list}' )
		monitor_mount_dir=${monitor_mount_dir_tmp/\|/}
	fi
	
	#定义ssl目录
	ssl_dir=~/.certs
	smtp_addr_port_ssl="smtps://$smtp_addr_port" #添加ssl协议头

	if [[ $ssl_enable -eq 1 ]];then	
		#判断磁盘使用率超过设定阈值,邮件告警通知
		for mount_dir in ${monitor_mount_dir//|/ }
		do
			disk_usage_result=$( get_disk_usage "$mount_dir" )
			if [[ ${disk_usage_result/\%/} -ge $alert_limit ]];then
				echo "Host name:${HOSTNAME} 

IP:$ip 

Disk $mount_dir usage $disk_usage_result exceeded limited ${alert_limit}%"|mailx -s "Host name:${HOSTNAME} Disk $mount_dir usage $disk_usage_result exceeded limited ${alert_limit}%" -S ssl-verify=ignore -S smtp-auth=login -S smtp="$smtp_addr_port_ssl" -S from="${mail_from}(Disk Usage Alert)" -S smtp-auth-user="$mail_user" -S smtp-auth-password="$mail_password" -S nss-config-dir="$ssl_dir" $mail_to 2>/dev/null
                sleep 3
			fi
		done
    else
		#判断磁盘使用率超过设定阈值,邮件告警通知(not ssl)
		for mount_dir in ${monitor_mount_dir//|/ }
		do
			disk_usage_result=$( get_disk_usage "$mount_dir" )
			if [[ ${disk_usage_result/\%/} -ge $alert_limit ]];then
				echo "Host name:${HOSTNAME} 

IP:$ip 

Disk $mount_dir usage $disk_usage_result exceeded limited ${alert_limit}%"|mailx -s "Host name:${HOSTNAME} Disk $mount_dir usage $disk_usage_result exceeded limited ${alert_limit}%" -S smtp-auth=login -S smtp="$smtp_addr_port" -S from="${mail_from}(Disk Usage Alert)" -S smtp-auth-user="$mail_user" -S smtp-auth-password="$mail_password" $mail_to 2>/dev/null
                sleep 3
			fi
		done
	fi
	
else
	die "open_mail_alert variable must 0 or 1"
fi
  • get_proc_stat.sh
#!/usr/bin/env bash
#===============================================================================
#
#          FILE: get_proc_stat.sh
# 
#         USAGE: ./get_proc_stat.sh [name|pid|arg] [value]
# 
#   DESCRIPTION: 根据进程名或PID或进程命令行参数查询进程,并输出相关进程信息
# 
#  ORGANIZATION: dqzboy.com
#===============================================================================

set -o nounset                              # Treat unset variables as an error

ok () {
    echo "$(date +%F\ %T)|$$|$BASH_LINENO|info|job success: $*" 
    exit 0
}

die () {
    echo "$(date +%F\ %T)|$$|$BASH_LINENO|error|job fail: $*" >&2
    exit 1
}

usage() { 
    cat <<_OO_
USAGE:
    get_proc_stat.sh [name|pid|arg] [value]

_OO_
    exit 1
}

# 通过/proc/下获取文件句柄和进程工作目录
get_pid_stat_proc() {
    local pids="$1"

    {
    shopt -s nullglob
    echo "CWD FH"
    for pid in ${pids/,/ /}; do
	cwd=$(readlink -f "/proc/$pid/cwd")
	fds=(/proc/$pid/fd/*)
	fd_cnt=${#fds[@]}
	[[ -z "$cwd" ]] && cwd="NULL"
	(( fd_cnt == 0 )) && fd_cnt="NOACCESS"
	echo "$cwd $fd_cnt"
    done
    } | column -t 
}

# 获取指定PID的所有子进程PID
get_chd_pid() {
    local chd_pids=$(pgrep -P "$1" | xargs)
    for cpid in $chd_pids; do
	echo "$cpid"
	get_chd_pid "$cpid"
    done
}

# 输出进程的所有子进程数量
get_pid_cpid_cnt() {
    local pids="$1"

    {
    shopt -s nullglob
    echo "CHD"
    for pid in ${pids/,/ }; do
	chd=$(get_chd_pid "$pid" | wc -l)
	echo "$chd"
    done
    } | column -t
}


# 汇总输出
get_pid_stat() {
    local pids="$1"

    if [[ -z "$pids" ]]; then
	die "no such process."
    fi

    # sort pids
    pids=$(echo "$pids" | sed s'/,/\n/g'  | sort -n | xargs | sed 's/ /,/g')

    ps_output=$(ps -p "$pids" -o pid,comm,user,pcpu,rss,stat,lstart)
    cwd_output=$(get_pid_stat_proc "$pids") 
    cpid_output=$(get_pid_cpid_cnt "$pids")
    paste <(echo "$ps_output") <(echo "$cwd_output") <(echo "$cpid_output")
}

if [[ $# -eq 2 ]]; then
    case $1 in 
	name)	pids=$(pgrep -d, -x "$2") ;;
	arg)	pids=$(pgrep -d, -f "$2") ;;
	pid) 	pids="$2" ;;
	*) 	usage ;;
    esac

    get_pid_stat "$pids"
else
    usage
fi
  • get_top_proc.sh
#!/usr/bin/env bash
#===============================================================================
#
#          FILE: get_top_proc.sh
# 
#         USAGE: ./get_top_proc.sh 
# 
#   DESCRIPTION: 输出系统当前占用资源(cpu、内存、IO、流量等等)最多的Top10进程
# 
#  ORGANIZATION: dqzboy.com
#===============================================================================

set -o nounset                              # Treat unset variables as an error

common_fields="pcpu,pmem,rss,pid,user,args"
IFS="," read -r -a common <<< "$common_fields"

usage() {
    cat <<EOF
    get_top_proc.sh <cpu|mem> <additional output fields>
    by default, output $common_fields fields
EOF
    exit 1
}

contains_string() {
    local e 
    for e in "${@:2}"; do
	[[ "$e" == "$1" ]] && return 0
    done
    return 1
}

join() {
    local IFS="$1"
    shift; echo "$*"
}

if (( $# < 1 )) || (( $# > 2 )) ; then
    usage
fi

case $1 in 
    cpu) sort_field=pcpu ;;
    mem) sort_field=rss ;;
    *) usage ;;
esac

if [[ $# -eq 1 ]]; then
    fields="$common_fields"
else
    IFS="," read -r -a extra <<< "$2"
    for f in "${extra[@]}";do
	contains_string "$f" "${common[@]}" || extra_fields+=("$f")
    done
    fields="$common_fields,$(join , "${extra_fields[@]}")"
fi

ps -eo "$fields" --sort=-"$sort_field" | head -10
  • get_top_proc_in_oneline.sh
#!/usr/bin/env bash
#===============================================================================
#
#          FILE: get_top_proc_in_oneline.sh
# 
#         USAGE: ./get_top_proc_in_oneline.sh <cpu|mem> <number>
# 
#   DESCRIPTION: 输出系统当前占用资源(cpu、内存)最多的TopN进程
# 
#  ORGANIZATION: dqzboy.com
#===============================================================================

set -o nounset                              # Treat unset variables as an error

fields="pcpu,pmem,comm"

usage() {
    cat <<EOF
    get_top_proc_in_oneline.sh <cpu|mem> <number of top proc>
EOF
    exit 1
}

join() {
    local IFS="$1"
    shift; echo "$*"
}

if (( $# < 1 )) || (( $# > 2 )) ; then
    usage
fi

case $1 in 
    cpu) sort_field=pcpu ;;
    mem) sort_field=rss ;;
    *) usage ;;
esac

if [[ $# -eq 2 ]]; then
    top_n=$2
else
    top_n=6
fi

ps -eo "$fields" --sort=-"$sort_field" | head -$(( top_n + 1 )) | awk 'NR==1 { gsub(/%/,"") } {printf "%s\\n", $0 }'

Linux脚本小工具


脚本功能:

  • manage_cron_tasks.sh:管理系统上所有用户的定时任务。通过选择是否删除每个用户的定时任务
  • modify_ip.sh:RHEL 8发行版OS 使用nmcli指令自动化修改网卡IP,配合NetworkManager使用
  • base64_menu.sh:用于实现base64加密和解密用户输入的内容

脚本项目地址:点此查看

脚本内容:

  • base64_menu.sh
#!/usr/bin/env bash
#===============================================================================
#
#          FILE: base64_menu.sh
# 
#         USAGE: ./base64_menu.sh
# 
#   DESCRIPTION: 用于实现base64加密和解密用户输入的内容
# 
#  ORGANIZATION: Ding Qinzheng   www.dqzboy.com
#       CREATED: 2023
#===============================================================================

GREEN="3[1;32m"
RESET="3[0m"
PURPLE="3[35m"
BOLD="3[1m"
CYAN="3[1;36m"
RED="3[1;31m"
OUTPUT_FILE="output.txt"
# 加密函数
encrypt() {
    read -e -p "$(echo -e ${GREEN}请输入要加密的内容: ${RESET})" text_to_encrypt
    if [[ -z "$text_to_encrypt" ]]; then
        echo -e "${RED}输入内容不能为空!${RESET}"
        return 1
    fi
    encrypted_text=$(echo -n "$text_to_encrypt" | base64)
    echo -e "${CYAN}加密结果为: $encrypted_text${RESET}"
    echo "加密内容:$text_to_encrypt  解密内容: $encrypted_text" >> $OUTPUT_FILE
    return 0
}
# 解密函数
decrypt() {
    read -e -p "$(echo -e ${GREEN}请输入要解密的base64内容: ${RESET})" text_to_decrypt
    if [[ -z "$text_to_decrypt" ]]; then
        echo -e "${RED}输入内容不能为空!${RESET}"
        return 1
    fi
    decrypted_text=$(echo -n "$text_to_decrypt" | base64 --decode)
    echo -e "${CYAN}解密结果为: $decrypted_text${RESET}"
    echo "解密内容:$decrypted_text  加密内容: $text_to_decrypt" >> $OUTPUT_FILE
    return 0
}
# 脚本主体
while true; do
    echo -e "${PURPLE}=====================${RESET}"
    echo -e "${PURPLE}=     ${BOLD}菜单选项${RESET}${PURPLE}     =${RESET}"
    echo -e "${PURPLE}=====================${RESET}"
    echo -e " ${BOLD}1.${RESET} 加密"
    echo -e " ${BOLD}2.${RESET} 解密"
    echo -e " ${BOLD}3.${RESET} 退出"
    echo -e "${PURPLE}=====================${RESET}"
    read -e -p "$(echo -e ${GREEN}选择操作: ${RESET})" option
    case "$option" in
        1)
            encrypt
            [[ $? -eq 0 ]] && exit 0  # 如果加密成功则退出脚本
            ;;
        2)
            decrypt
            [[ $? -eq 0 ]] && exit 0  # 如果解密成功则退出脚本
            ;;
        3)
            echo -e "${CYAN}退出程序...${RESET}"
            exit 0
            ;;
        *)
            echo -e "${RED}无效选项,请重新选择。${RESET}"
            ;;
    esac
done
  • manage_cron_tasks.sh
#!/usr/bin/env bash
#===============================================================================
#
#          FILE: manage_cron_tasks.sh
# 
#         USAGE: ./manage_cron_tasks.sh
# 
#   DESCRIPTION: 管理系统上所有用户的定时任务。通过选择是否删除每个用户的定时任务
# 
#  ORGANIZATION: dqzboy.com
#       CREATED: 2022
#===============================================================================

# 获取所有用户列表
user_list=$(cut -d: -f1 /etc/passwd)

# 初始化标志变量,用于判断是否有用户有定时任务
has_cron_tasks=false

# 遍历用户列表
for user in $user_list
do
    # 查看用户的cron任务
    cron_tasks=$(crontab -u $user -l 2>/dev/null)
    
    # 如果用户有定时任务
    if [ -n "$cron_tasks" ]; then
        has_cron_tasks=true
        echo "User: $user"
        echo "Cron Tasks:"
        echo "$cron_tasks"
        echo "====================="
        
        # 询问用户是否删除该用户的定时任务
        read -p "Do you want to delete cron tasks for $user? (y/n): " delete_choice
        if [ "$delete_choice" == "y" ]; then
            # 询问用户删除第几条或全部
            read -p "Enter the task number(s) to delete (e.g., 1 3 5 for specific tasks, a for all tasks): " task_numbers
            if [ "$task_numbers" == "a" ]; then
                # 删除所有定时任务
                crontab -r -u $user
                echo "All cron tasks deleted for $user."
            else
                # 备份用户的原始定时任务
                original_cron_tasks=$(mktemp)
                crontab -u $user -l > "$original_cron_tasks"

                # 删除指定定时任务
                for task_number in $task_numbers
                do
                    sed -i "${task_number}d" "$original_cron_tasks"
                done

                # 恢复修改后的定时任务
                crontab -u $user "$original_cron_tasks"
                rm "$original_cron_tasks"
                echo "Selected cron tasks deleted for $user."
            fi
        fi
    fi
done

# 如果所有用户都没有定时任务,则打印提示信息
if [ "$has_cron_tasks" == false ]; then
    echo "No cron tasks found for any user."
fi
  • modify_ip.sh
#!/usr/bin/env bash
#===============================================================================
#
#          FILE: modify_ip.sh
# 
#         USAGE: ./modify_ip.sh
# 
#   DESCRIPTION: RHEL 8发行版OS 使用nmcli指令自动化修改网卡IP,配合NetworkManager使用
# 
#  ORGANIZATION: dqzboy.com
#       CREATED: 2022
#===============================================================================



# 颜色定义
GREEN_LIGHT="3[1;32m"
RED="3[0;31m"
CYAN="3[0;36m"
NC="3[0m" # 恢复默认颜色

# 显示连接服务器的提示
function display_connect_instructions() {
    local connect_instructions="${RED}脚本执行完成后,必须使用以下 IP 重新连接服务器!${NC}"
    local interface="$1"
    local new_ip="$2"

    # 构建虚线框
    local frame_length=${#connect_instructions}
    local frame=""
    for ((i=1; i<=frame_length+4; i++)); do
        frame+="-"
    done

    echo -e "${CYAN}+${frame}+${NC}"
    echo -e "${CYAN}|  ${connect_instructions}  ${CYAN}|${NC}"
    echo -e "${CYAN}+${frame}+${NC}"
}

# 显示可用的网络接口
function display_interfaces() {
    echo "可用的网络接口:"
    nmcli device status
}

# 加载并修改 nmcli 连接配置为静态IP
function modify_connection() {
    local interface="$1"
    local new_ip="$2"
    local gateway="$3"
    local subnet_mask="$4"
    local dns_servers="$5"

    nmcli connection modify "$interface" ipv4.addresses "$new_ip/$subnet_mask" ipv4.gateway "$gateway" ipv4.dns "$dns_servers" ipv4.method manual connection.autoconnect yes

    # 检查是否执行成功
    if [ $? -eq 0 ]; then
        echo -e "${GREEN_LIGHT}已将 $interface 的网络配置修改为静态IP:IP地址:$new_ip,网关:$gateway,DNS服务器:$dns_servers${NC}"
    else
        echo -e "${RED}修改 $interface 的网络配置失败。请检查输入信息和网络接口是否正确,并重新执行脚本。${NC}"
        exit 1
    fi
}

# 检查用户输入的IP地址和子网掩码格式是否正确
function check_ip_format() {
    local ip="$1"

    # 使用正则表达式检查IP地址和子网掩码格式
    if [[ $ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+$ ]]; then
        return 0
    else
        return 1
    fi
}

# 提示用户输入网络配置信息
function prompt_for_network_config() {
    local interface="$1"

    # 循环提示用户输入,直到格式正确
    while true; do
        read -e -p "$(echo -e "${GREEN_LIGHT}请输入 $interface 的新 IP 地址和子网掩码(格式为IP/子网掩码):${NC}")" new_ip

        # 检查用户输入是否是有效的 IP 地址和子网掩码格式
        if check_ip_format "$new_ip"; then
            break
        else
            echo -e "${GREEN_LIGHT}错误:无效的 IP 地址和子网掩码格式。请重新输入一个有效的 IPv4 地址和子网掩码。${NC}"
        fi
    done

    read -e -p "$(echo -e "${GREEN_LIGHT}请输入 $interface 的网关地址:${NC}")" gateway
    read -e -p "$(echo -e "${GREEN_LIGHT}请输入 $interface 的DNS服务器地址(多个DNS服务器用空格分隔):${NC}")" dns_servers

    # 解析用户输入的IP地址和子网掩码
    local new_ip_address="$(echo "$new_ip" | cut -d'/' -f1)"
    local subnet_mask="$(echo "$new_ip" | cut -d'/' -f2)"

    modify_connection "$interface" "$new_ip_address" "$gateway" "$subnet_mask" "$dns_servers"
    nmcli con down "$interface" && nmcli con up "$interface"
}

# 获取当前活动的网络接口名称
active_interface=$(nmcli device status | grep -E '\sconnected\s' | awk '{print $1}')

# 提示用户使用修改后的网络配置连接服务器
if [ -n "$active_interface" ]; then
    display_connect_instructions "$active_interface" "$new_ip"
    prompt_for_network_config "$active_interface"
else
    echo -e "${GREEN_LIGHT}错误:未找到活动的网络接口。${NC}"
    display_interfaces
    exit 1
fi

Linux软件服务


脚本功能:

  • get_port_info.sh:获取指定服务端口的统计信息
  • uptime-kuma_install.sh:一键部署 uptime-kuma 监控平台工具

脚本项目地址:点此查看

脚本内容:

  • get_port_info.sh文章来源(Source):浅时光博客
#!/usr/bin/env bash
#===============================================================================
#
#          FILE: get_port_info.sh
# 
#         USAGE: ./get_port_info.sh [-h] [-i ip] -p <port>
# 
#   DESCRIPTION: 获取指定服务端口的统计信息
# 
#  ORGANIZATION: dqzboy.com
#===============================================================================

set -o nounset                              # Treat unset variables as an error

export LC_ALL=C
export LANG=C

usage() {
    cat <<EOF
    Usage: $0 [-h] [-i ip] -p <port>
EOF
    exit 1
}

precheck() {
    if ! which ss &> /dev/null; then
        echo "ss not found, try install iproute2 package first"        
        exit 1
    fi

    if [[ $( id -u ) != 0 ]]; then
        echo "$0 should run under root"
        exit 1
    fi
}

get_service_name(){
    local port=$1
    local proto=$2

    local service=$( grep -E '^[a-z]' /etc/services  | 
        awk -vport=$port -v proto=$proto '{ if ( $2 == port"/"proto ) { print $1; exit 0 } } ' 
    )

    [[ -z $service ]] && services="N/A"
    echo $service
}

################################################################################

port=
proto=tcp

while getopts "i:p:h" arg; do
    case $arg in
        i)
            ip=$OPTARG
            ;;
        p)
            port=$OPTARG
            ;;
        h|?)
            usage >&2
            exit 1
            ;;
    esac
done


if [[ -z $port ]]; then
    usage
fi

precheck

tmpf=$( mktemp )
ss -lant 2>/dev/null | sed -e 's/::/*/' -e 's/:/\t/g' > "$tmpf"

listen_ip=$( awk -vport=$port '{ if ($1 == "LISTEN" && $5 == port) { print $4; } }' "$tmpf" | sort -u | xargs | tr ' ' ',' )
if [[ -z $listen_ip ]]; then
    echo -e "Listen ip:\tN/A"
    exit 1
fi

echo -e "Listen ip:\t$listen_ip"
echo -e "Protocol:\ttcp"
echo -e "Port:\t$port"
echo -e "Service:\t$( get_service_name $port $proto)"
echo -e "Connections:"

awk -vport=$port '{ 
        if ( $1 != "LISTEN" && $5 == port ) { stat[$1]++ } 
    } 
    END { 
        for (s in stat) { print "\t"s":\t"stat[s] }  
    } ' "$tmpf"

/bin/rm "$tmpf"
  • uptime-kuma_install.sh
#!/usr/bin/env bash
#===============================================================================
#
#          FILE: uptime-kuma_install.sh
#
#         USAGE: ./uptime-kuma_install.sh
#
#   DESCRIPTION: 一键部署 uptime-kuma 监控平台工具
#
#  ORGANIZATION: DingQz dqzboy.com
#===============================================================================
SETCOLOR_SKYBLUE="echo -en \\E[1;36m"
SETCOLOR_SUCCESS="echo -en \\E[0;32m"
SETCOLOR_NORMAL="echo  -en \\E[0;39m"
SETCOLOR_RED="echo  -en \\E[0;31m"
SETCOLOR_YELLOW="echo -en \\E[1;33m"
GREEN="3[1;32m"
RESET="3[0m"
PURPLE="3[35m"


SUCCESS() {
  ${SETCOLOR_SUCCESS} && echo "------------------------------------< $1 >-------------------------------------"  && ${SETCOLOR_NORMAL}
}

SUCCESS1() {
  ${SETCOLOR_SUCCESS} && echo "$1"  && ${SETCOLOR_NORMAL}
}

ERROR() {
  ${SETCOLOR_RED} && echo "$1"  && ${SETCOLOR_NORMAL}
}

INFO() {
  ${SETCOLOR_SKYBLUE} && echo "------------------------------------ $1 -------------------------------------"  && ${SETCOLOR_NORMAL}
}

INFO1() {
  ${SETCOLOR_SKYBLUE} && echo "$1"  && ${SETCOLOR_NORMAL}
}

WARN() {
  ${SETCOLOR_YELLOW} && echo "$1"  && ${SETCOLOR_NORMAL}
}


function CHECK_OS() {
if [ -f /etc/os-release ]; then
    . /etc/os-release
else
    echo "无法确定发行版"
    exit 1
fi


# 根据发行版选择存储库类型
case "$ID" in
    "centos")
        repo_type="centos"
        ;;
    "debian")
        repo_type="debian"
        ;;
    "rhel")
        repo_type="rhel"
        ;;
    "ubuntu")
        repo_type="ubuntu"
        ;;
    "opencloudos")
        repo_type="centos"
        ;;
    "rocky")
        repo_type="centos"
        ;;
    *)
        WARN "此脚本暂不支持您的系统: $ID"
        exit 1
        ;;
esac

echo "------------------------------------------"
echo "系统发行版: $NAME"
echo "系统版本: $VERSION"
echo "系统ID: $ID"
echo "系统ID Like: $ID_LIKE"
echo "------------------------------------------"
}


function INSTALL_DOCKER() {
# 定义存储库文件名
repo_file="docker-ce.repo"
# 下载存储库文件
url="https://download.docker.com/linux/$repo_type"

if [ "$repo_type" = "centos" ] || [ "$repo_type" = "rhel" ]; then
    if ! command -v docker &> /dev/null;then
      while [ $attempt -lt $MAX_ATTEMPTS ]; do
        attempt=$((attempt + 1))
        ERROR "docker 未安装,正在进行安装..."
        yum-config-manager --add-repo $url/$repo_file &>/dev/null
        yum -y install docker-ce &>/dev/null
        # 检查命令的返回值
        if [ $? -eq 0 ]; then
            success=true
            break
        fi
        echo "docker安装失败,正在尝试重新下载 (尝试次数: $attempt)"
      done

      if $success; then
         SUCCESS1 ">>> $(docker --version)"
         systemctl restart docker | grep -E "ERROR|ELIFECYCLE|WARN"
         systemctl enable docker &>/dev/null
      else
         ERROR "docker安装失败,请尝试手动安装"
         exit 1
      fi
    else
      INFO1 "docker 已安装..."
      SUCCESS1 ">>> $(docker --version)"
      systemctl restart docker | grep -E "ERROR|ELIFECYCLE|WARN"
    fi
elif [ "$repo_type" == "ubuntu" ]; then
    if ! command -v docker &> /dev/null;then
      while [ $attempt -lt $MAX_ATTEMPTS ]; do
        attempt=$((attempt + 1))
        ERROR "docker 未安装,正在进行安装..."
        curl -fsSL $url/gpg | sudo apt-key add - &>/dev/null
        add-apt-repository "deb [arch=amd64] $url $(lsb_release -cs) stable" <<< $'\n' &>/dev/null
        apt-get -y install docker-ce docker-ce-cli containerd.io &>/dev/null
        # 检查命令的返回值
        if [ $? -eq 0 ]; then
            success=true
            break
        fi
        echo "docker安装失败,正在尝试重新下载 (尝试次数: $attempt)"
      done

      if $success; then
         SUCCESS1 ">>> $(docker --version)"
         systemctl restart docker | grep -E "ERROR|ELIFECYCLE|WARN"
         systemctl enable docker &>/dev/null
      else
         ERROR "docker安装失败,请尝试手动安装"
         exit 1
      fi
    else
      INFO1 "docker 已安装..."
      SUCCESS1 ">>> $(docker --version)"
      systemctl restart docker | grep -E "ERROR|ELIFECYCLE|WARN"
    fi
elif [ "$repo_type" == "debian" ]; then
    if ! command -v docker &> /dev/null;then
      while [ $attempt -lt $MAX_ATTEMPTS ]; do
        attempt=$((attempt + 1))

        ERROR "docker 未安装,正在进行安装..."
        curl -fsSL $url/gpg | sudo apt-key add - &>/dev/null
        add-apt-repository "deb [arch=amd64] $url $(lsb_release -cs) stable" <<< $'\n' &>/dev/null
        apt-get -y install docker-ce docker-ce-cli containerd.io &>/dev/null
	# 检查命令的返回值
        if [ $? -eq 0 ]; then
            success=true
            break
        fi
        echo "docker安装失败,正在尝试重新下载 (尝试次数: $attempt)"
      done

      if $success; then
         SUCCESS1 ">>> $(docker --version)"
         systemctl restart docker | grep -E "ERROR|ELIFECYCLE|WARN"
         systemctl enable docker &>/dev/null
      else
         ERROR "docker安装失败,请尝试手动安装"
         exit 1
      fi
    else
      INFO1 "docker 已安装..."
      SUCCESS1 ">>> $(docker --version)"
      systemctl restart docker | grep -E "ERROR|ELIFECYCLE|WARN"
    fi
else
    ERROR "Unsupported operating system."
    exit 1
fi
}

function ADD_UPTIME_KUMA() {
    SUCCESS "Uptime Kuma"
    read -e -p "$(echo -e ${GREEN}"是否部署uptime-kuma监控工具?(y/n): "${RESET})" uptime

    if [[ "$uptime" == "y" ]]; then
        # 检查是否已经运行了 uptime-kuma 容器
        if docker ps -a --format "{{.Names}}" | grep -q "uptime-kuma"; then
            WARN "已经运行了uptime-kuma监控工具。"
            read -e -p "$(echo -e ${GREEN}"是否停止和删除旧的容器并继续安装?(y/n): "${RESET})" continue_install

            if [[ "$continue_install" == "y" ]]; then
                docker stop uptime-kuma
                docker rm uptime-kuma
                INFO1 "已停止和删除旧的uptime-kuma容器。"
            else
                INFO1 "已取消部署uptime-kuma监控工具。"
                exit 0
            fi
        fi

        MAX_TRIES=3

        for ((try=1; try<=${MAX_TRIES}; try++)); do
            read -e -p "$(echo -e ${GREEN}"请输入监听的端口: "${RESET})" UPTIME_PORT

            # 检查端口是否已被占用
            if ss -tulwn | grep -q ":${UPTIME_PORT} "; then
                ERROR "端口 ${UPTIME_PORT} 已被占用,请尝试其他端口。"
                if [ "${try}" -lt "${MAX_TRIES}" ]; then
                    WARN "您还有 $((${MAX_TRIES} - ${try})) 次尝试机会。"
                else
                    ERROR "您已用尽所有尝试机会。"
                    exit 1
                fi
            else
                break
            fi
        done

        # 提示用户输入映射的目录
        read -e -p "$(echo -e ${GREEN}"请输入数据持久化在宿主机上的目录路径: "${RESET})" MAPPING_DIR
        # 检查目录是否存在,如果不存在则创建
        if [ ! -d "${MAPPING_DIR}" ]; then
            mkdir -p "${MAPPING_DIR}"
            INFO1 "目录已创建:${MAPPING_DIR}"
        fi

        # 启动 Docker 容器
        docker run -d --restart=always -p "${UPTIME_PORT}":3001 -v "${MAPPING_DIR}":/app/data --name uptime-kuma louislam/uptime-kuma:1
        # 检查 uptime-kuma 容器状态
        status_uptime=`docker container inspect -f '{{.State.Running}}' uptime-kuma 2>/dev/null`

        # 判断容器状态并打印提示
        if [[ "$status_uptime" == "true" ]]; then
            SUCCESS "CHECK"
            Progress
            SUCCESS1 ">>>>> Docker containers are up and running."
            INFO1 "uptime-kuma 安装完成,请使用浏览器访问 IP:${UPTIME_PORT} 进行访问。"
        else
            SUCCESS "CHECK"
            Progress
            ERROR ">>>>> The following containers are not up"
            if [[ "$status_uptime" != "true" ]]; then
                ERROR "uptime-kuma 安装过程中出现问题,请检查日志或手动验证容器状态。"
            fi
        fi
    elif [[ "$uptime" == "n" ]]; then
        # 取消部署uptime-kuma
        WARN "已取消部署uptime-kuma监控工具!"
    else
        ERROR "选项错误!请重新运行脚本并选择正确的选项。"
        exit 1
    fi
}


main() {
  CHECK_OS
  INSTALL_DOCKER
  ADD_UPTIME_KUMA
}
main

本文作者:浅时光博客
原文链接:https://www.dqzboy.com/16239.html
版权声明:知识共享署名-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)协议进行许可,转载时请以>超链接形式标明文章原始出处和作者信息
免责声明:本站内容仅供个人学习与研究,严禁用于商业或非法目的。请在下载后24小时内删除相应内容。继续浏览或下载即表明您接受上述条件,任何后果由用户自行承担。

0 条回应

必须 注册 为本站用户, 登录 后才可以发表评论!