shell脚本练习2023年下岗版

news2024/11/28 3:36:41

shell脚本练习

1.判断指定进程的运行情况

#!/bin/bash
NAME=httpd #这里输入进程的名称
NUM=$(ps -ef |grep $NAME |grep -vc grep)
if [ $NUM -eq 1 ]; then
    echo "$NAME running."
else
    echo "$NAME is not running!"
fi

2.判断用户是否存在

#!/bin/bash
read -p "请输入用户:" user
for i in `awk -F :  '{print $1}' /etc/passwd`
do
        if [ $i == $user ]
        then
                echo "用户已存在!"
                exit
        else
                isfind=false
        fi
done
echo "用户不存在!"

3.生成随机数

#!/bin/bash
read -p "请输入随机生成的数字位数:" num
echo $RANDOM | cksum | cut -c 1-$num

4.判断软件包是否安装

#!/bin/bash
read -p "请输入要查询的软件包:" software

if rpm -q $software &>/dev/null ;

then

    echo "软件包已经安装!"

else

    echo "软件包未安装!"

fi

5.判断主机是否存活

ip_list="192.168.254.1 192.168.254.10" #定义一个主机列表
for ip in $ip_list;do
        NUM=1
        while [ $NUM -le 3 ];do
                if ping -c 1 $ip > /dev/null;then
                        echo "$ip 存在于网络中!"
                        break
                else
                        echo "$ip 不存在于网络中!"
                        break
                fi
        done
done

6.判断指定主机端口状态

HOST=127.0.0.1 #被扫描主机
PORT="22 80 8080" #指定需要扫描的端口
for PORT in $PORT; do #进行for循环
        if echo &>/dev/null > /dev/tcp/$HOST/$PORT; then
                echo    "$PORT open"
        else
                echo    "$PORT close"
        fi
done

7.获取主机IP地址

#!/bin/bash 
IP=$(ip address show | awk '/^[0-9]+: / {}; /inet.*global/ {print gensub(/(.*)\/(.*)/, "\\1", "g", $2)}')
echo "$IP"

8.判断文件或目录是否存在

#!/bin/bash

if [ $# -eq 0 ];then
    echo "未输入任何参数,请输入参数"
    echo "用法:$0 [文件名 | 目录名]"
fi

if [ -f $1 ]; then
    echo "该文件 存在"
    ls -l $1
elif [ -d $1 ]; then
    echo "该目录 存在"
    ls -ld $1
else
    echo "该文件or目录 不存在"
fi

9.显示系统信息

#!/bin/bash
#
HOSTNAME=`hostname`
IP=`ip a show ens33 | grep "inet" | grep -v "inet6" | awk '{print $2}' | cut -d'/' -f1`
SYSTEM=`cat /etc/centos-release`
CORE=`uname -r`
CPU=`cat /proc/cpuinfo | grep 'model name' |uniq | cut -d: -f2`
MEMORY=`free -mh | grep -i "mem" | awk '{print$2}'`
DISKNUM=`fdisk -l | grep -i "/dev" | grep -i "disk" | wc -l`
systemname=("HOSTNAME" "IP" "SYSTEM VERSION" "CORE VERSION" "CPU" "MEMORY SIZE")
systeminfo=("$HOSTNAME" "$IP" "$SYSTEM" "$CORE" "$CPU" "$MEMORY")
for s in `seq 1 $DISKNUM`;do
    eval DISK$s=`fdisk -l | grep -i "/dev" | grep -i "disk" | head -$s | tail -1|  awk '{print $2$3$4}' | cut -d',' -f1`
    eval systeminfo[$(($s+5))]='$'DISK$s
    systemname[$(($s+5))]="DISK$s SIZE"
done
for i in ${!systeminfo[*]};do
    echo "--------------------------------------------------------------"
    printf "|%-15s| %-43s|\n" "${systemname[$i]}" "${systeminfo[$i]}"
done
echo "--------------------------------------------------------------"

10.判断输入的是否为IP地址

#!/bin/bash
IP=$1
if [[ $IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
   FIELD1=$(echo $IP|cut -d. -f1)
   FIELD2=$(echo $IP|cut -d. -f2)
   FIELD3=$(echo $IP|cut -d. -f3)
   FIELD4=$(echo $IP|cut -d. -f4)
   if [ $FIELD1 -le 255 -a $FIELD2 -le 255 -a $FIELD3 -le 255 -a $FIELD4 -le 255 ]; 
   then
            echo "$IP 是一个IP地址!"
        else
            echo "$IP 不是一个IP地址!"
        fi
    else
        echo "IP地址格式错误!"
fi

11.sys_info.sh

#!/bin/bash

localip=$(ifconfig ens33 | grep netmask | tr -s " " | cut -d " " -f3)
mem=$(free | grep Mem | tr -s " " | cut -d " " -f7)
cpu=$(uptime | tr -s " " | cut -d " " -f11)

echo "IP address:$localip"
echo "Memory surplus:$mem"
echo "CPU load:$cpu"

12、测试计算机的CPU品牌是AMD还是Intel

cpu_info.sh

#!/bin/bash

if grep -q AMD /proc/cpuinfo; then
echo "AMD CPU"

fi

if grep -q Intel /proc/cpuinfo; then

echo "Intel CPU"
fi

13、服务状态监控

check_service.sh

#!/bin/bash

if [ -z $1 ];then
	echo "error:No server name was entered"
	echo "Usage: script name   +   server name"
	exit

fi

if systemctl is-active $1 &>/dev/null; then
	echo "$1 have already started"
else
	echo "$1 unstart"

fi

if systemctl is-enabled $1 &>/dev/null; then
	echo "$1 Is the boot auto option"
else
	echo "$1 Not start auto option"
fi	
	

14、通过读取位置变量,实现分区管理工作

#!/bin/bash

if [ $# -ne 2 ];then
	echo -e "usage: <disk name> <create|new|remove|query>"
	exit
fi

#测试磁盘是否存在

if [ ! -b $1 ];then
	echo -e "disk nonentity"
	exit
fi

#根据不同的指令对磁盘进行分区管理

if [[ $2 == create ]];then
	parted -s $1 mklabel gpt
elif [[ $2 == new ]];then
	parted -s $1 mkpart primary 1 100%
elif [[ $2 == remove ]];then
	parted -s $1 rm 1
elif [[ $2 == query ]];then
	parted -s $1 print
else
	clear
	echo -e "operation error"
	echo "use:[cr
	eate|new|remove|query]."
fi

15、查看系统信息的脚本

#!/bin/bash

echo "输入一个选项"

select item in "CPU" "IP" "MEM" "exit"
do
	case $item in
		"CPU")
			uptime;;
		"IP")
			ip a s;;
		"MEM")
			free;;
		"exit")
			exit;;
		*)
			echo error;;
	esac
done

16、通过文件重定向读取文件解决子shell问题

#!/bin/bash


tmp_file="/tmp/subshell-?.txt"
df | grep "^/" > $tmp_file
while read name total used free other
do
	let sum+=free
done < $tmp_file
rm -rf $tmp_file
echo $sum

17、多进程的ping脚本

本脚本的功能就是使用函数与&后台进程实现多进程ping测试。

#!/bin/bash

net="192.168.43"
multi_ping_fun(){
	ping -c2 -i0.2 -W1 $1 &>/dev/null
	if [ $? -eq 0 ];then
		echo "$1 is up"
	else
		echo "$1 is down"
	fi
}

for i in {1..254}
do
	multi_ping_fun $net.$i &
done
#!/bin/bash

net="192.168.43"
multi_ping_fun(){
	ping -c2 -i0.2 -W1 $1 &>/dev/null
	if [ $? -eq 0 ];then
		echo "$1 is up"
	else
		echo "$1 is down"
	fi
}

#通过循环反复调用函数并将其放入后台并行执行
for i in {1..254}
do
	multi_ping_fun $net.$i &
done
wait

18、循环对多个文件进行备份操作

#!/bin/bash

for i in `ls /etc/*.conf`
do
	tar -czf /home/minger/share/tencent/shell/$(basename $i).tar.gz $i
done

19、使用进程号或进程数量生成随机数

#!/bin/bash


#根据进程号生成随机文件

touch /tmp/?.tmp

#根据进程数量生成随机文件

pnum=`ps aux | wc -l`
touch /tmp/$pnum.tmp

#根据文件个数生成随机文件

fnum=`find /etc | wc -l`
touch /tmp/$fnum.tmp

#根据文件行数生成随机文件

cnum=`cat /var/log/messages | wc -l`
touch /tmp/$cnum.tmp

20、Shell 版本的进度条功能

#!/bin/bash


#防止提前按Ctrl +C 组合键后无法结束进度条

trap 'kill $!' INT

bar(){
	while :
	do
		echo -n '#'
		sleep 0.3
	done
}

bar &
cp -r $1 $2
kill $!
echo "复制结束!"

21使用Hydra配合脚本批量暴力破解

#!/bin/bash
random=$RANDOM
 
if [ $# -lt 4 ] 
then
   echo "usage: ./hydra-ssh.sh -u root -p ./passwd.txt -s 22 -x ssh -f ./iplist.txt"
   echo "usage: ./hydra.sh -u root -p ./passwd.txt -s 22 -x ssh -l 192.168.9.0/24"
   exit 1
fi
 
while [ -n "$1" ]  
do  
  case "$1" in    
    -u)  
        user=$2
        shift  
        ;;  
    -p)  
        passfile=$2
        shift  
        ;;  
    -s)  
        port=$2
        shift  
        ;; 
    -x)  
        term=$2
        shift  
        ;; 
    -f)  
        cat $2 > /tmp/IPaddress-output-$random.txt
        shift  
        ;;  
    -l)  
        nmap -vv -n -sS -sU -p$port $2  | grep "Discovered open port" | awk {'print $6'} | awk -F/ {'print $1'} > /tmp/IPaddress-output-$random.txt 
        shift  
        ;; 
    *)  
        echo "$1 is not an option"  
        echo "usage: ./hydra.sh -u root -p ./passwd.txt -s 22 -x ssh -f ./iplist.txt"
        echo "usage: ./hydra.sh -u root -p ./passwd.txt -s 22 -x ssh -l 192.168.9.0/24"
        exit 1
        ;;  
  esac  
  shift  
done
 
echo "-----------Port Scan Finished-----------" >> ./Result-hydra.txt
 
chmod 666 /tmp/IPaddress-output-$random.txt
 
cat /tmp/IPaddress-output-$random.txt | while read line
do 
    echo "Current Task: ${line}" >> ./Result-hydra.txt
    hydra -q -l $user -P $passfile -t 4 -vV -s $port $line $term | grep "host:" >> ./Result-hydra.txt
done
 
echo "-------Password Guessing Finished-------" >> ./Result-hydra.txt
 
rm -rf /tmp/IPaddress-output-$random.txt
cat ./Result-hydra.txt | grep "host:"

22Linux 系统发送告警脚本

# yum install mailx
# vi /etc/mail.rc
set from=baojingtongzhi@163.com smtp=smtp.163.com
set smtp-auth-user=baojingtongzhi@163.com smtp-auth-password=123456
set smtp-auth=login

23MySQL 数据库备份单循环

#!/bin/bash
DATE=$(date +%F_%H-%M-%S)
HOST=localhost
USER=backup
PASS=123.com
BACKUP_DIR=/data/db_backup
DB_LIST=$(mysql -h$HOST -u$USER -p$PASS -s -e "show databases;" 2>/dev/null |egrep -v "Database|information_schema|mysql|performance_schema|sys")

for DB in $DB_LIST; do
    BACKUP_NAME=$BACKUP_DIR/${DB}_${DATE}.sql
    if ! mysqldump -h$HOST -u$USER -p$PASS -B $DB > $BACKUP_NAME 2>/dev/null; then
        echo "$BACKUP_NAME 备份失败!"
    fi
done

24MySQL 数据库备份多循环

#!/bin/bash
DATE=$(date +%F_%H-%M-%S)
HOST=localhost
USER=backup
PASS=123.com
BACKUP_DIR=/data/db_backup
DB_LIST=$(mysql -h$HOST -u$USER -p$PASS -s -e "show databases;" 2>/dev/null |egrep -v "Database|information_schema|mysql|performance_schema|sys")

for DB in $DB_LIST; do
    BACKUP_DB_DIR=$BACKUP_DIR/${DB}_${DATE}
    [ ! -d $BACKUP_DB_DIR ] && mkdir -p $BACKUP_DB_DIR &>/dev/null
    TABLE_LIST=$(mysql -h$HOST -u$USER -p$PASS -s -e "use $DB;show tables;" 2>/dev/null)
    for TABLE in $TABLE_LIST; do
        BACKUP_NAME=$BACKUP_DB_DIR/${TABLE}.sql
        if ! mysqldump -h$HOST -u$USER -p$PASS $DB $TABLE > $BACKUP_NAME 2>/dev/null; then
            echo "$BACKUP_NAME 备份失败!"
        fi
    done
done

25Nginx 访问日志按天切割

#!/bin/bash
LOG_DIR=/usr/local/nginx/logs
YESTERDAY_TIME=$(date -d "yesterday" +%F)
LOG_MONTH_DIR=$LOG_DIR/$(date +"%Y-%m")
LOG_FILE_LIST="default.access.log"

for LOG_FILE in $LOG_FILE_LIST; do
    [ ! -d $LOG_MONTH_DIR ] && mkdir -p $LOG_MONTH_DIR
    mv $LOG_DIR/$LOG_FILE $LOG_MONTH_DIR/${LOG_FILE}_${YESTERDAY_TIME}
done

kill -USR1 $(cat /var/run/nginx.pid)

26Nginx 访问日志分析脚本

#!/bin/bash
# 日志格式: $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"
LOG_FILE=$1
echo "统计访问最多的10个IP"
awk '{a[$1]++}END{print "UV:",length(a);for(v in a)print v,a[v]}' $LOG_FILE |sort -k2 -nr |head -10
echo "----------------------"

echo "统计时间段访问最多的IP"
awk '$4>="[01/Dec/2018:13:20:25" && $4<="[27/Nov/2018:16:20:49"{a[$1]++}END{for(v in a)print v,a[v]}' $LOG_FILE |sort -k2 -nr|head -10
echo "----------------------"

echo "统计访问最多的10个页面"
awk '{a[$7]++}END{print "PV:",length(a);for(v in a){if(a[v]>10)print v,a[v]}}' $LOG_FILE |sort -k2 -nr
echo "----------------------"

echo "统计访问页面状态码数量"
awk '{a[$7" "$9]++}END{for(v in a){if(a[v]>5)print v,a[v]}}'

27查看网卡实时流量脚本

#!/bin/bash
NIC=$1
echo -e " In ------ Out"
while true; do
    OLD_IN=$(awk '$0~"'$NIC'"{print $2}' /proc/net/dev)
    OLD_OUT=$(awk '$0~"'$NIC'"{print $10}' /proc/net/dev)
    sleep 1
    NEW_IN=$(awk  '$0~"'$NIC'"{print $2}' /proc/net/dev)
    NEW_OUT=$(awk '$0~"'$NIC'"{print $10}' /proc/net/dev)
    IN=$(printf "%.1f%s" "$((($NEW_IN-$OLD_IN)/1024))" "KB/s")
    OUT=$(printf "%.1f%s" "$((($NEW_OUT-$OLD_OUT)/1024))" "KB/s")
    echo "$IN $OUT"
    sleep 1
done

28服务器系统配置初始化脚本

#/bin/bash
# 设置时区并同步时间
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
if ! crontab -l |grep ntpdate &>/dev/null ; then
    (echo "* 1 * * * ntpdate time.windows.com >/dev/null 2>&1";crontab -l) |crontab
fi

# 禁用selinux
sed -i '/SELINUX/{s/permissive/disabled/}' /etc/selinux/config

# 关闭防火墙
if egrep "7.[0-9]" /etc/redhat-release &>/dev/null; then
    systemctl stop firewalld
    systemctl disable firewalld
elif egrep "6.[0-9]" /etc/redhat-release &>/dev/null; then
    service iptables stop
    chkconfig iptables off
fi

# 历史命令显示操作时间
if ! grep HISTTIMEFORMAT /etc/bashrc; then
    echo 'export HISTTIMEFORMAT="%F %T `whoami` "' >> /etc/bashrc
fi

# SSH超时时间
if ! grep "TMOUT=600" /etc/profile &>/dev/null; then
    echo "export TMOUT=600" >> /etc/profile
fi

# 禁止root远程登录
sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config

# 禁止定时任务向发送邮件
sed -i 's/^MAILTO=root/MAILTO=""/' /etc/crontab

# 设置最大打开文件数
if ! grep "* soft nofile 65535" /etc/security/limits.conf &>/dev/null; then
    cat >> /etc/security/limits.conf << EOF
    * soft nofile 65535
    * hard nofile 65535
EOF
fi

# 系统内核优化
cat >> /etc/sysctl.conf << EOF
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_tw_buckets = 20480
net.ipv4.tcp_max_syn_backlog = 20480
net.core.netdev_max_backlog = 262144
net.ipv4.tcp_fin_timeout = 20
EOF

# 减少SWAP使用
echo "0" > /proc/sys/vm/swappiness

# 安装系统性能分析工具及其他
yum install gcc make autoconf vim sysstat net-tools iostat if

29监控 100 台服务器磁盘利用率脚本

#!/bin/bash
HOST_INFO=host.info
for IP in $(awk '/^[^#]/{print $1}' $HOST_INFO); do
    USER=$(awk -v ip=$IP 'ip==$1{print $2}' $HOST_INFO)
    PORT=$(awk -v ip=$IP 'ip==$1{print $3}' $HOST_INFO)
    TMP_FILE=/tmp/disk.tmp
    ssh -p $PORT $USER@$IP 'df -h' > $TMP_FILE
    USE_RATE_LIST=$(awk 'BEGIN{OFS="="}/^\/dev/{print $NF,int($5)}' $TMP_FILE)
    for USE_RATE in $USE_RATE_LIST; do
        PART_NAME=${USE_RATE%=*}
        USE_RATE=${USE_RATE#*=}
        if [ $USE_RATE -ge 80 ]; then
            echo "Warning: $PART_NAME Partition usage $USE_RATE%!"
        fi
    done
done

30通过位置变量创建 Linux 系统账户及密码

#!/bin/bash
# 通过位置变量创建 Linux 系统账户及密码
#$1 是执行脚本的第一个参数,$2 是执行脚本的第二个参数
useradd "$1"
echo "$2" | passwd ‐‐stdin "$1"

31备份日志

#!/bin/bash
# 每周 5 使用 tar 命令备份/var/log 下的所有日志文件
# vim /root/logbak.sh
# 编写备份脚本,备份后的文件名包含日期标签,防止后面的备份将前面的备份数据覆盖
# 注意 date 命令需要使用反引号括起来,反引号在键盘<tab>键上面
tar	-czf	log-`date +%Y%m%d`.tar.gz	/var/log
# crontab ‐e	#编写计划任务,执行备份脚本
00	03	*	*	5	/root/logbak.sh

32一键部署 LNMP(RPM 包版本)

#!/bin/bash
# 一键部署 LNMP(RPM 包版本)
# 使用 yum 安装部署 LNMP,需要提前配置好 yum 源,否则该脚本会失败
# 本脚本使用于 centos7.2 或 RHEL7.2
yum ‐y install httpd
yum ‐y install mariadb mariadb‐devel mariadb‐server
yum ‐y install php php‐mysql
systemctl start httpd mariadb
systemctl enable httpd mariadb

33监控内存和磁盘容量,小于给定值时报警

#!/bin/bash
# 实时监控本机内存和硬盘剩余空间,剩余内存小于500M、根分区剩余空间小于1000M时,
#发送报警邮件给root管理员提取根分区剩余空间
disk_size=$(df / | awk '/\//{print $4}')
# 提取内存剩余空间
mem_size=$(free | awk '/Mem/{print $4}')
while :
do
# 注意内存和磁盘提取的空间大小都是以 Kb 为单位
if [ $disk_size -le 512000 -a $mem_size -le 1024000 ]
then
mail ‐s "Warning" root <<EOF
Insufficient resources,资源不足
EOF
fi
done

34猜数字游戏

#!/bin/bash
# 脚本生成一个 100 以内的随机数,提示用户猜数字,根据用户的输入,提示用户猜对了,
# 猜小了或猜大了,直至用户猜对脚本结束。
# RANDOM 为系统自带的系统变量,值为 0‐32767的随机数
# 使用取余算法将随机数变为 1‐100 的随机数
num=$[RANDOM%100+1]
echo "$num"
# 使用 read 提示用户猜数字
# 使用 if 判断用户猜数字的大小关系:‐eq(等于),‐ne(不等于),‐gt(大于),‐ge(大于等于),
# ‐lt(小于),‐le(小于等于)
while :
do
read -p "计算机生成了一个 1‐100 的随机数,你猜: " cai
if [ $cai -eq $num ]
then
echo "恭喜,猜对了"
exit
elif [ $cai -gt $num ]
then
echo "Oops,猜大了"
else
echo "Oops,猜小了"
fi
done

35检测本机当前用户是否为超级管理员,如果是管理员,则使用 yum 安装 vsftpd,如果不是,则提示您非管理员(使用字串对比版本)

#!/bin/bash
# 检测本机当前用户是否为超级管理员,如果是管理员,则使用 yum 安装 vsftpd,如果不
# 是,则提示您非管理员(使用字串对比版本)
if [ $USER == "root" ]
then
yum ‐y install vsftpd
else
echo "您不是管理员,没有权限安装软件"
fi

36使用 UID 数字对比版本

#!/bin/bash
# 检测本机当前用户是否为超级管理员,如果是管理员,则使用 yum 安装 vsftpd,如果不
# 是,则提示您非管理员(使用 UID 数字对比版本)
if [ $UID -eq 0 ];then
yum ‐y install vsftpd
else
echo "您不是管理员,没有权限安装软件"
fi

37编写脚本:提示用户输入用户名和密码,脚本自动创建相应的账户及配置密码。如果用户不输入账户名,则提示必须输入账户名并退出脚本;如果用户不输入密码,则统一使用默认的 123456 作为默认密码。

#!/bin/bash
# 编写脚本:提示用户输入用户名和密码,脚本自动创建相应的账户及配置密码。如果用户
# 不输入账户名,则提示必须输入账户名并退出脚本;如果用户不输入密码,则统一使用默
# 认的 123456 作为默认密码。
read -p "请输入用户名: " user
#使用‐z 可以判断一个变量是否为空,如果为空,提示用户必须输入账户名,并退出脚本,退出码为 2
#没有输入用户名脚本退出后,使用$?查看的返回码为 2
if [ -z $user ];then
echo "您不需输入账户名"
exit 2
fi
#使用 stty ‐echo 关闭 shell 的回显功能
#使用 stty echo 打开 shell 的回显功能
stty -echo
read -p "请输入密码: " pass
stty echo
pass=${pass:‐123456}
useradd "$user"
echo "$pass" | passwd ‐‐stdin "$user"

38输入三个数并进行升序排序

#!/bin/bash
# 依次提示用户输入 3 个整数,脚本根据数字大小依次排序输出 3 个数字
read -p "请输入一个整数:" num1
read -p "请输入一个整数:" num2
read -p "请输入一个整数:" num3
# 不管谁大谁小,最后都打印 echo "$num1,$num2,$num3"
# num1 中永远存最小的值,num2 中永远存中间值,num3 永远存最大值
# 如果输入的不是这样的顺序,则改变数的存储顺序,如:可以将 num1 和 num2 的值对调
tmp=0
# 如果 num1 大于 num2,就把 num1 和和 num2 的值对调,确保 num1 变量中存的是最小值
if [ $num1 -gt $num2 ];then
tmp=$num1
num1=$num2
num2=$tmp
fi
# 如果 num1 大于 num3,就把 num1 和 num3 对调,确保 num1 变量中存的是最小值
if [ $num1 -gt $num3 ];then
tmp=$num1
num1=$num3
num3=$tmp
fi
# 如果 num2 大于 num3,就把 num2 和 num3 对标,确保 num2 变量中存的是小一点的值
if [ $num2 -gt $num3 ];then
tmp=$num2
num2=$num3
num3=$tmp
fi
echo "排序后数据(从小到大)为:$num1,$num2,$num3"

39石头、剪刀、布游戏

#!/bin/bash
# 编写脚本,实现人机<石头,剪刀,布>游戏
game=(石头 剪刀 布)
num=$[RANDOM%3]
computer=${game[$num]}
# 通过随机数获取计算机的出拳
# 出拳的可能性保存在一个数组中,game[0],game[1],game[2]分别是 3 
#中不同的可能
echo "请根据下列提示选择您的出拳手势"
echo "1.石头"
echo "2.剪刀"
echo "3.布"
read -p "请选择 1‐3:" person
case $person in
1)
if [ $num -eq 0 ]
then
echo "平局"
elif [ $num -eq 1 ]
then
echo "你赢"
else
echo "计算机赢"
fi;;
2)
if [ $num -eq 0 ]
then
echo "计算机赢"
elif [ $num -eq 1 ]
then
echo "平局"
else
echo "你赢"
fi;;
3)
if [ $num -eq 0 ]
then
echo "你赢"
elif [ $num -eq 1 ]
then
echo "计算机赢"
else
echo "平局"
fi;;
*)
echo "必须输入 1‐3 的数字"
esac

41编写脚本测试 192.168.4.0/24 整个网段中哪些主机处于开机状态,哪些主机处于关机状态(for 版本)

#!/bin/bash
# 编写脚本测试 192.168.4.0/24 整个网段中哪些主机处于开机状态,
#哪些主机处于关机状态(for 版本)
for i in {1..254}
do
# 每隔0.3秒ping一次,一共ping2次,并以1毫秒为单位设置ping的超时时间
ping ‐c 2 ‐i 0.3 ‐W 1 192.168.4.$i &>/dev/null
if [ $? -eq 0 ];then
echo "192.168.4.$i is up"
else
echo "192.168.4.$i is down"
fi
done

42编写脚本测试 192.168.4.0/24 整个网段中哪些主机处于开机状态,哪些主机处于关机状态(while 版本)

#!/bin/bash
# 编写脚本测试 192.168.4.0/24 整个网段中哪些主机处于开机状态,
#哪些主机处于关机状态(while 版本)
i=1
while [ $i -le 254 ]
do
ping ‐c 2 ‐i 0.3 ‐W 1 192.168.4.$i &>/dev/null
if [ $? -eq 0 ];then
echo "192.168.4.$i is up"
else
echo "192.168.4.$i is down"
fi
let i++
done

43编写脚本测试 192.168.4.0/24 整个网段中哪些主机处于开机状态,哪些主机处于关机状态(多进程版)

#!/bin/bash
# 编写脚本测试 192.168.4.0/24 整个网段中哪些主机处于开机状态,
# 哪些主机处于关机状态(多进程版)
# 定义一个函数,ping 某一台主机,并检测主机的存活状态
myping(){
ping ‐c 2 ‐i 0.3 ‐W 1 $1 &>/dev/null
if [ $? -eq 0 ];then
echo "$1 is up"
else
echo "$1 is down"
fi
}
for i in {1..254}
do
myping 192.168.4.$i &
done
# 使用&符号,将执行的函数放入后台执行
# 这样做的好处是不需要等待ping第一台主机的回应,
#就可以继续并发ping第二台主机,依次类推。

44编写脚本,显示进度条

#!/bin/bash
# 编写脚本,显示进度条
jindu(){
while :
do
echo -n '#'
sleep 0.2
done
}
jindu &
cp -a $1 $2
killall $0
echo "拷贝完成"

45进度条,动态时针版本;定义一个显示进度的函数,屏幕快速显示| / ‐ \

#!/bin/bash
# 进度条,动态时针版本
# 定义一个显示进度的函数,屏幕快速显示| / ‐ \
rotate_line(){
INTERVAL=0.5 #设置间隔时间
COUNT="0" #设置4个形状的编号,默认编号为 0(不代表任何图像)
while :
do
COUNT=`expr $COUNT + 1` 
#执行循环,COUNT 每次循环加 1,(分别代表4种不同的形状)
case $COUNT in #判断 COUNT 的值,值不一样显示的形状就不一样
"1") #值为 1 显示‐
echo -e '‐'"\b\c"
sleep $INTERVAL
;;
"2") #值为 2 显示\\,第一个\是转义
echo -e '\\'"\b\c"
sleep $INTERVAL
;;
"3") #值为 3 显示|
echo -e "|\b\c"
sleep $INTERVAL
;;
"4") #值为 4 显示/
echo -e "/\b\c"
sleep $INTERVAL
;;
*) #值为其他时,将 COUNT 重置为 0
COUNT="0";;
esac
done
}
rotate_line

46,9*9 乘法表

#!/bin/bash
# 9*9 乘法表(编写 shell 脚本,打印 9*9 乘法表)
for i in `seq 9`
do
for j in `seq $i`
do
echo -n "$j*$i=$[i*j] "
done
echo
done

47. 使用死循环实时显示 eth0 网卡发送的数据包流量

#!/bin/bash
# 使用死循环实时显示 eth0 网卡发送的数据包流量
while :
do
echo '本地网卡 eth0 流量信息如下: '
ifconfig eth0 | grep "RX pack" | awk '{print $5}'
ifconfig eth0 | grep "TX pack" | awk '{print $5}'
sleep 1
done

48使用 user.txt 文件中的人员名单,在计算机中自动创建对应的账户并配置初始密码本脚本执行,需要提前准备一个 user.txt 文件,该文件中包含有若干用户名信息

#!/bin/bash
# 使用 user.txt 文件中的人员名单,在计算机中自动创建对应的账户并配置初始密码
# 本脚本执行,需要提前准备一个 user.txt 文件,该文件中包含有若干用户名信息
for i in `cat user.txt`
do
useradd $i
echo "123456" | passwd ‐‐stdin $i
done

49编写批量修改扩展名脚本

#!/bin/bash
# 编写批量修改扩展名脚本,如批量将 txt 文件修改为 doc 文件
# 执行脚本时,需要给脚本添加位置参数
# 脚本名 txt doc(可以将 txt 的扩展名修改为 doc)
# 脚本名 doc jpg(可以将 doc 的扩展名修改为 jpg)
for i in "ls *.$1"
do
mv $i ${i%.*}.$2
done

50使用 expect 工具自动交互密码远程其他主机安装 httpd 软件

#!/bin/bash
# 使用 expect 工具自动交互密码远程其他主机安装 httpd 软件
# 删除~/.ssh/known_hosts 后,ssh 远程任何主机都会询问是否确认要连接该主机
rm ‐rf ~/.ssh/known_hosts
expect <<EOF
spawn ssh 192.168.4.254
expect "yes/no" {send "yes\r"}
# 根据自己的实际情况将密码修改为真实的密码字串
expect "password" {send "密码\r"}
expect "#" {send "yum ‐y install httpd\r"}
expect "#" {send "exit\r"}
EOF

51一键部署 LNMP(源码安装版本)

#!/bin/bash
# 一键部署 LNMP(源码安装版本)
menu()
{
clear
echo " ##############‐‐‐‐Menu‐‐‐‐##############"
echo "# 1. Install Nginx"
echo "# 2. Install MySQL"
echo "# 3. Install PHP"
echo "# 4. Exit Program"
echo " ########################################"
}
choice()
{
read -p "Please choice a menu[1‐9]:" select
}
install_nginx()
{
id nginx &>/dev/null
if [ $? -ne 0 ];then
useradd -s /sbin/nologin nginx
fi
if [ -f nginx‐1.8.0.tar.gz ];then
tar -xf nginx‐1.8.0.tar.gz
cd nginx‐1.8.0
yum -y install gcc pcre‐devel openssl‐devel zlib‐devel make
./configure ‐‐prefix=/usr/local/nginx ‐‐with‐http_ssl_module
make
make install
ln -s /usr/local/nginx/sbin/nginx /usr/sbin/
cd ..
else
echo "没有 Nginx 源码包"
fi
}
install_mysql()
{
yum -y install gcc gcc‐c++ cmake ncurses‐devel perl
id mysql &>/dev/null
if [ $? -ne 0 ];then
useradd -s /sbin/nologin mysql
fi
if [ -f mysql‐5.6.25.tar.gz ];then
tar -xf mysql‐5.6.25.tar.gz
cd mysql‐5.6.25
cmake .
make
make install
/usr/local/mysql/scripts/mysql_install_db ‐‐user=mysql ‐‐datadir=/usr/local/mysql/data/
‐‐basedir=/usr/local/mysql/
chown -R root.mysql /usr/local/mysql
chown -R mysql /usr/local/mysql/data
/bin/cp -f /usr/local/mysql/support‐files/mysql.server /etc/init.d/mysqld
chmod +x /etc/init.d/mysqld
/bin/cp -f /usr/local/mysql/support‐files/my‐default.cnf /etc/my.cnf
echo "/usr/local/mysql/lib/" >> /etc/ld.so.conf
ldconfig
echo 'PATH=\$PATH:/usr/local/mysql/bin/' >> /etc/profile
export PATH
else
echo "没有 mysql 源码包"
exit
fi
}
install_php()
{
#安装 php 时没有指定启动哪些模块功能,
#如果的用户可以根据实际情况自行添加额外功能如‐‐with‐gd 等
yum -y install gcc libxml2‐devel
if [ -f mhash‐0.9.9.9.tar.gz ];then
tar -xf mhash‐0.9.9.9.tar.gz
cd mhash‐0.9.9.9
./configure
make
make install
cd ..
if [ ! ‐f /usr/lib/libmhash.so ];then
ln -s /usr/local/lib/libmhash.so /usr/lib/
fi
ldconfig
else
echo "没有 mhash 源码包文件"
exit
fi
if [ -f libmcrypt‐2.5.8.tar.gz ];then
tar -xf libmcrypt‐2.5.8.tar.gz
cd libmcrypt‐2.5.8
./configure
make
make install
cd ..
if [ ! -f /usr/lib/libmcrypt.so ];then
ln -s /usr/local/lib/libmcrypt.so /usr/lib/
fi
ldconfig
else
echo "没有 libmcrypt 源码包文件"
exit
fi
if [ -f php‐5.4.24.tar.gz ];then
tar -xf php‐5.4.24.tar.gz
cd php‐5.4.24
./configure ‐‐prefix=/usr/local/php5 ‐‐with‐mysql=/usr/local/mysql ‐‐enable‐fpm ‐‐
enable‐mbstring ‐‐with‐mcrypt ‐‐with‐mhash ‐‐with‐config‐file‐path=/usr/local/php5/etc ‐‐with‐
mysqli=/usr/local/mysql/bin/mysql_config
make && make install
/bin/cp -f php.ini‐production /usr/local/php5/etc/php.ini
/bin/cp -f /usr/local/php5/etc/php‐fpm.conf.default /usr/local/php5/etc/php‐fpm.conf
cd ..
else
echo "没有 php 源码包文件"
exit
fi
}
while :
do
menu
choice
case $select in
1)
install_nginx
;;
2)
install_mysql
;;
3)
install_php
;;
4)
exit
;;
*)
echo Sorry!
esac
done

52点名器脚本

#!/bin/bash
# 编写一个点名器脚本
# 该脚本,需要提前准备一个 user.txt 文件
# 该文件中需要包含所有姓名的信息,一行一个姓名,脚本每次随机显示一个姓名
while :
do
#统计 user 文件中有多少用户
line=`cat user.txt |wc ‐l`
num=$[RANDOM%line+1]
sed -n "${num}p" user.txt
sleep 0.2
clear
done

53查看有多少远程的 IP 在连接本机

#!/bin/bash
# 查看有多少远程的 IP 在连接本机(不管是通过 ssh 还是 web 还是 ftp 都统计)
# 使用 netstat ‐atn 可以查看本机所有连接的状态,‐a 查看所有,
# -t仅显示 tcp 连接的信息,‐n 数字格式显示
# Local Address(第四列是本机的 IP 和端口信息)
# Foreign Address(第五列是远程主机的 IP 和端口信息)
# 使用 awk 命令仅显示第 5 列数据,再显示第 1 列 IP 地址的信息
# sort 可以按数字大小排序,最后使用 uniq 将多余重复的删除,并统计重复的次数
netstat -atn | awk '{print $5}' | awk '{print $1}' | sort -nr | uniq -c

54对 100 以内的所有正整数相加求和(1+2+3+4…+100)

#!/bin/bash
# 对 100 以内的所有正整数相加求和(1+2+3+4...+100)
#seq 100 可以快速自动生成 100 个整数
sum=0
for i in `seq 100`
do
sum=$[sum+i]
done
echo "总和是:$sum"

55统计 13:30 到 14:30 所有访问 apache 服务器的请求有多少个

#!/bin/bash
# 统计 13:30 到 14:30 所有访问 apache 服务器的请求有多少个
# awk 使用‐F 选项指定文件内容的分隔符是/或者:
# 条件判断$7:$8 大于等于 13:30,并且要求,$7:$8 小于等于 14:30
# 最后使用 wc ‐l 统计这样的数据有多少行,即多少个
awk -F "[ /:]" '$7":"$8>="13:30" && $7":"$8<="14:30"' /var/log/httpd/access_log |wc -l

56统计 13:30 到 14:30 所有访问本机 Aapche 服务器的远程 IP 地址是什么

#!/bin/bash
# 统计 13:30 到 14:30 所有访问本机 Aapche 服务器的远程 IP 地址是什么
# awk 使用‐F 选项指定文件内容的分隔符是/或者:
# 条件判断$7:$8 大于等于 13:30,并且要求,$7:$8 小于等于 14:30
# 日志文档内容里面,第 1 列是远程主机的 IP 地址,使用 awk 单独显示第 1 列即可
awk -F "[ /:]" '$7":"$8>="13:30" && $7":"$8<="14:30"{print $1}' /var/log/httpd/access_log

57. 统计每个远程 IP 访问了本机 apache 几次?

#!/bin/bash
# 统计每个远程 IP 访问了本机 apache 几次?
awk '{ip[$1]++}END{for(i in ip){print ip[i],i}}' /var/log/httpd/access_log

58统计当前 Linux 系统中可以登录计算机的账户有多少个

#!/bin/bash
# 统计当前 Linux 系统中可以登录计算机的账户有多少个
#方法 1:
grep "bash$" /etc/passwd | wc -l
#方法 2:
awk -f: '/bash$/{x++}end{print x}' /etc/passwd

59统计/var/log 有多少个文件,并显示这些文件名

#!/bin/bash
# 统计/var/log 有多少个文件,并显示这些文件名
# 使用 ls 递归显示所有,再判断是否为文件,如果是文件则计数器加 1
cd /var/log
sum=0
for i in `ls -r *`
do
if [ -f $i ];then
let sum++
echo "文件名:$i"
fi
done
echo "总文件数量为:$sum"

60自动为其他脚本添加解释器信息

#!/bin/bash
# 自动为其他脚本添加解释器信息#!/bin/bash,如脚本名为 test.sh 则效果如下:
# ./test.sh abc.sh	自动为 abc.sh 添加解释器信息
# ./test.sh user.sh	自动为 user.sh 添加解释器信息
# 先使用 grep 判断对象脚本是否已经有解释器信息,如果没有则使用 sed 添加解释器以及描述信息
if ! grep -q "^#!" $1; then
sed '1i #!/bin/bash' $1
sed '2i #Description: '
fi
# 因为每个脚本的功能不同,作用不同,所以在给对象脚本添加完解释器信息,
# 以及 Description 后还希望继续编辑具体的脚本功能的描述信息,
# 这里直接使用 vim 把对象脚本打开,并且光标跳转到该文件的第 2 行
vim +2 $1

61编写 nginx 启动脚本

#!/bin/bash
# 编写 nginx 启动脚本
# 本脚本编写完成后,放置在/etc/init.d/目录下,就可以被 Linux 系统自动识别到该脚本
# 如果本脚本名为/etc/init.d/nginx,则 service nginx start 就可以启动该服务
# service nginx stop 就可以关闭服务
# service nginx restart 可以重启服务
# service nginx status 可以查看服务状态
program=/usr/local/nginx/sbin/nginx
pid=/usr/local/nginx/logs/nginx.pid
start(){
if [ -f $pid ];then
echo "nginx 服务已经处于开启状态"
else
$program
fi
stop(){
if [ -! -f $pid ];then
echo "nginx 服务已经关闭"
else
$program -s stop
echo "关闭服务 ok"
fi
}
status(){
if [ -f $pid ];then
echo "服务正在运行..."
else
echo "服务已经关闭"
fi
}
case $1 in
start)
start;;
stop)
stop;;
restart)
stop
sleep 1
start;;
status)
status;;
*)
echo "你输入的语法格式错误"
esac

62自动对磁盘分区、格式化、挂载

#!/bin/bash
# 自动对磁盘分区、格式化、挂载
# 对虚拟机的 vdb 磁盘进行分区格式化,使用<<将需要的分区指令导入给程序 fdisk
# n(新建分区),p(创建主分区),1(分区编号为 1),两个空白行(两个回车,相当于将整个磁盘分一个区)
# 注意:1 后面的两个回车(空白行)是必须的!
fdisk /dev/vdb << EOF
n
p
1
wq
EOF
#格式化刚刚创建好的分区
mkfs.xfs /dev/vdb1
#创建挂载点目录
if [ -e /data ]; then
exit
fi
mkdir /data
#自动挂载刚刚创建的分区,并设置开机自动挂载该分区
echo '/dev/vdb1 /data xfs defaults 1 2' >> /etc/fstab
mount -a

63自动优化 Linux 内核参数

#!/bin/bash
# 自动优化 Linux 内核参数
#脚本针对 RHEL7
cat >> /usr/lib/sysctl.d/00‐system.conf <<EOF
fs.file‐max=65535
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_synack_retries = 5
net.ipv4.tcp_syn_retries = 5
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
#net.ipv4.tcp_keepalive_time = 120
net.ipv4.ip_local_port_range = 1024 65535
kernel.shmall = 2097152
kernel.shmmax = 2147483648
kernel.shmmni = 4096
kernel.sem = 5010 641280 5010 128
net.core.wmem_default=262144
net.core.wmem_max=262144
net.core.rmem_default=4194304
net.core.rmem_max=4194304
net.ipv4.tcp_fin_timeout = 10
net.ipv4.tcp_keepalive_time = 30
net.ipv4.tcp_window_scaling = 0
net.ipv4.tcp_sack = 0
EOF
sysctl –p

64切割 Nginx 日志文件(防止单个文件过大,后期处理很困难)

#mkdir /data/scripts
#vim /data/scripts/nginx_log.sh
#!/bin/bash
# 切割 Nginx 日志文件(防止单个文件过大,后期处理很困难)
logs_path="/usr/local/nginx/logs/"
mv ${logs_path}access.log ${logs_path}access_$(date -d "yesterday" +"%Y%m%d").log
kill -USR1 `cat /usr/local/nginx/logs/nginx.pid`
# chmod +x /data/scripts/nginx_log.sh
# crontab ‐e #脚本写完后,将脚本放入计划任务每天执行一次脚本
0 1 * * * /data/scripts/nginx_log.sh

65检测 MySQL 数据库连接数量

#!/bin/bash
# 检测 MySQL 数据库连接数量
# 本脚本每 2 秒检测一次 MySQL 并发连接数,可以将本脚本设置为开机启动脚本,或在特定时间段执行
# 以满足对 MySQL 数据库的监控需求,查看 MySQL 连接是否正常
# 本案例中的用户名和密码需要根据实际情况修改后方可使用
log_file=/var/log/mysql_count.log
user=root
passwd=123456
while :
do
sleep 2
count=`mysqladmin -u "$user" -p "$passwd" status | awk '{print $4}'`
echo "`date +%Y‐%m‐%d` 并发连接数为:$count" >> $log_file
done

66备份 MySQL 的 shell 脚本(mysqldump版本)

#!/bin/bash
# 备份 MySQL 的 shell 脚本(mysqldump版本)
# 定义变量 user(数据库用户名),passwd(数据库密码),date(备份的时间标签)
# dbname(需要备份的数据库名称,根据实际需求需要修改该变量的值,默认备份 mysql 数据库)
user=root
passwd=123456
dbname=mysql
date=$(date +%Y%m%d)
# 测试备份目录是否存在,不存在则自动创建该目录
[ ! -d /mysqlbackup ] && mkdir /mysqlbackup
# 使用 mysqldump 命令备份数据库
mysqldump -u "$user" -p "$passwd" "$dbname" > /mysqlbackup/"$dbname"-${date}.sql

67将文件中所有的小写字母转换为大写字母

#!/bin/bash
# 将文件中所有的小写字母转换为大写字母
# $1是位置参数,是你需要转换大小写字母的文件名称
# 执行脚本,给定一个文件名作为参数,脚本就会将该文件中所有的小写字母转换为大写字母
tr "[a‐z]" "[A‐Z]" < $1

68检查特定的软件包是否已经安装

#!/bin/bash
# 检查特定的软件包是否已经安装
if [ $# -eq 0 ];then
echo "你需要制定一个软件包名称作为脚本参数"
echo "用法:$0 软件包名称 ..."
fi
# $@提取所有的位置变量的值,相当于$*
for package in "$@"
do
if rpm -q ${package} &>/dev/null ;then
echo -e "${package}\033[32m 已经安装\033[0m"
else
echo -e "${package}\033[34;1m 未安装\033[0m"
fi
done

69监控 HTTP 服务器的状态(测试返回码)

#!/bin/bash
# 监控 HTTP 服务器的状态(测试返回码)
# 设置变量,url为你需要检测的目标网站的网址(IP 或域名),比如百度
url=http://http://183.232.231.172/index.html
# 定义函数 check_http:
# 使用 curl 命令检查 http 服务器的状态
# ‐m 设置curl不管访问成功或失败,最大消耗的时间为 5 秒,5 秒连接服务为相应则视为无法连接
# ‐s 设置静默连接,不显示连接时的连接速度、时间消耗等信息
# ‐o 将 curl 下载的页面内容导出到/dev/null(默认会在屏幕显示页面内容)
# ‐w 设置curl命令需要显示的内容%{http_code},指定curl返回服务器的状态码
check_http()
{
status_code=$(curl -m 5 -s -o /dev/null -w %{http_code} $url)
}
while :
do
check_http
date=$(date +%Y%m%d‐%H:%M:%S)
# 生成报警邮件的内容
echo "当前时间为:$date
$url 服务器异常,状态码为${status_code}.
请尽快排查异常." > /tmp/http$$.pid
# 指定测试服务器状态的函数,并根据返回码决定是发送邮件报警还是将正常信息写入日志
if [ $status_code -ne 200 ];then
mail -s Warning root < /tmp/http$$.pid
else
echo "$url 连接正常" >> /var/log/http.log
fi
sleep 5
done

70使用脚本自动创建逻辑卷

#!/bin/bash
# 使用脚本自动创建逻辑卷
# 清屏,显示警告信息,创建将磁盘转换为逻辑卷会删除数据
clear
echo -e "\033[32m !!!!!!警告(Warning)!!!!!!\033[0m"
echo
echo "+++++++++++++++++++++++++++++++++++++++++++++++++"
echo "脚本会将整个磁盘转换为 PV,并删除磁盘上所有数据!!!"
echo "This Script will destroy all data on the Disk"
echo "+++++++++++++++++++++++++++++++++++++++++++++++++"
echo
read -p "请问是否继续 y/n?:" sure
# 测试用户输入的是否为 y,如果不是则退出脚本
[ $sure != y ] && exit
# 提示用户输入相关参数(磁盘、卷组名称等数据),并测试用户是否输入了这些值,如果没有输入,则脚本退出
read -p "请输入磁盘名称,如/dev/vdb:" disk
[ -z $disk ] && echo "没有输入磁盘名称" && exit
read -p "请输入卷组名称:" vg_name
[ -z $vg_name ] && echo "没有输入卷组名称" && exit
read -p "请输入逻辑卷名称:" lv_name
[ -z $lv_name ] && echo "没有输入逻辑卷名称" && exit
read -p "请输入逻辑卷大小:" lv_size
[ -z $lv_size ] && echo "没有输入逻辑卷大小" && exit
# 使用命令创建逻辑卷
pvcreate $disk
vgcreate $vg_name $disk
lvcreate -L ${lv_size}M -n ${lv_name} ${vg_name}

71删除某个目录下大小为 0 的文件

#!/bin/bash
# 除某个目录下大小为 0 的文件
#/var/www/html 为测试目录,脚本会清空该目录下所有 0 字节的文件
dir="/var/www/html"
find $dir -type f -size 0 -exec rm -rf {} \;

72查找 Linux 系统中的僵尸进程

#!/bin/bash
# 查找 Linux 系统中的僵尸进程
# awk 判断 ps 命令输出的第 8 列为 Z 是,显示该进程的 PID 和进程命令
ps aux | awk '{if($8 == "Z"){print $2,$11}}'

73循环测试用户名与密码是否正确

#!/bin/bash
# 循环测试用户名与密码是否正确
# 循环测试用户的账户名和密码,最大测试 3 次,输入正确提示登录成功,否则提示登录失败
# 用户名为 tom 并且密码为 123456
for i in {1..3}
do
read -p "请输入用户名:" user
read -p "请输入密码:" pass
if [ "$user" == 'tom' -a "$pass" == '123456' ];then
echo "Login successful"
exit
fi
done
echo "Login Failed"

74显示当前计算机中所有账户的用户名称

#!/bin/bash
# 显示当前计算机中所有账户的用户名称
# 下面使用3种不同的方式列出计算机中所有账户的用户名
# 指定以:为分隔符,打印/etc/passwd 文件的第 1 列
awk -F: '{print $1}' /etc/passwd
# 指定以:为分隔符,打印/etc/passwd 文件的第 1 列
cut -d: -f1 /etc/passwd
# 使用 sed 的替换功能,将/etc/passwd 文件中:后面的所有内容替换为空(仅显示用户名)
sed 's/:.*//' /etc/passwd

75制定目录路径,脚本自动将该目录使用 tar 命令打包备份到/data目录

#!/bin/bash
# 制定目录路径,脚本自动将该目录使用 tar 命令打包备份到/data目录
[ ! -d /data ] && mkdir /data
[ -z $1 ] && exit
if [ -d $1 ];then
tar -czf /data/$1.-`date +%Y%m%d`.tar.gz $1
else
echo "该目录不存在"
fi

76安装 LAMP 环境(yum 版本)

#!/bin/bash
# 安装 LAMP 环境(yum 版本)
# 本脚本适用于 RHEL7(RHEL6 中数据库为 mysql)
yum makecache &>/dev/null
num=$(yum repolist | awk '/repolist/{print $2}' | sed 's/,//')
if [ $num -lt 0 ];then
yum -y install httpd
yum -y install mariadb mariadb-server mariadb-devel
yum -y install php php-mysql
else
echo "未配置 yum 源..."
fi

77获取本机 MAC 地址

#!/bin/bash
# 获取本机 MAC 地址
ip a s | awk 'BEGIN{print " 本 机 MAC 地 址 信 息 如 下 :"}/^[0‐9]/{print $2;getline;if($0~/link\/ether/){print $2}}' | grep -v lo:
# awk 读取 ip 命令的输出,输出结果中如果有以数字开始的行,先显示该行的地 2 列(网卡名称),
# 接着使用 getline 再读取它的下一行数据,判断是否包含 link/ether
# 如果保护该关键词,就显示该行的第 2 列(MAC 地址)
# lo 回环设备没有 MAC,因此将其屏蔽,不显示

78修改 Linux 系统的最大打开文件数量

#!/bin/bash
# 修改 Linux 系统的最大打开文件数量
# 往/etc/security/limits.conf 文件的末尾追加两行配置参数,修改最大打开文件数量为 65536
cat >> /etc/security/limits.conf <<EOF
* soft nofile 65536
* hard nofile 65536
EOF

79统计 Linux 进程相关数量信息

#!/bin/bash
# 统计 Linux 进程相关数量信息
running=0
sleeping=0
stoped=0
zombie=0
# 在 proc 目录下所有以数字开始的都是当前计算机正在运行的进程的进程 PID
# 每个 PID 编号的目录下记录有该进程相关的信息
for pid in /proc/[1‐9]*
do
procs=$[procs+1]
stat=$(awk '{print $3}' $pid/stat)
# 每个 pid 目录下都有一个 stat 文件,该文件的第 3 列是该进程的状态信息
case $stat in
R)
running=$[running+1]
;;
T)
stoped=$[stoped+1]
;;
S)
sleeping=$[sleeping+1]
;;
Z)
zombie=$[zombie+1]
;;
esac
done
echo "进程统计信息如下"
echo "总进程数量为:$procs"
echo "Running 进程数为:$running"
echo "Stoped 进程数为:$stoped"
echo "Sleeping 进程数为:$sleeping"
echo "Zombie 进程数为:$zombie"

80显示本机 Linux 系统上所有开放的端口列表

#!/bin/bash
# 显示本机 Linux 系统上所有开放的端口列表
# 从端口列表中观测有没有没用的端口,有的话可以将该端口对应的服务关闭,防止意外的攻击可能性
ss -nutlp | awk '{print $1,$5}' | awk -F"[: ]" '{print "协议:"$1,"端口号:"$NF}' | grep "[0‐9]" | uniq

81将 Linux 系统中 UID 大于等于 1000 的普通用户都删除

#!/bin/bash
# 将 Linux 系统中 UID 大于等于 1000 的普通用户都删除
# 先用 awk 提取所有 uid 大于等于 1000 的普通用户名称
# 再使用 for 循环逐个将每个用户删除即可
user=$(awk -F: '$3>=1000{print $1}' /etc/passwd)
for i in $user
do
userdel -r $i
done

82,Shell脚本对Linux进行文件校验

一、需求

有客户等保需求对文件一致性进行校验,想到利用md5sum工具,因此写脚本来对文件进行自定义扫描,后期可以利用其进行校验,快速校验文件发现变更的文件,一定程度及时发现行为。

二、脚本

利用md5sum将扫描得到的文件保存在/tmp目录下,后缀为时间戳,后期可以利用此文件进行校验

#!/bin/bash
#func:scan file
#md5sum -c $SCAN_FILE


SCAN_DIR=`echo $PATH |sed 's/:/ /g'`
SCAN_CMD=`which md5sum`
SCAN_FILE_FAIL="/tmp/scan_$(date +%F%H%m)_fall.txt"
SCAN_FILE_BIN="/tmp/scan_$(date +%F%H%m)_bin.txt"

scan_fall_disk() {
	echo "正在全盘扫描,请稍等!文件路径:$SCAN_FILE_FALL"
	find / -type f ! -path "/proc/*" -exec $SCAN_CMD \{\} \;>> $SCAN_FILE_FAIL 2>/dev/null
	echo "扫描完成,可利用以下命令后期对文件进行校验"
	echo "$SCAN_CMD -c $SCAN_FILE_FAIL |grep -v 'OK$'"
}

scan_bin() {
	echo "正在扫描$PATH可执行文件,请稍等,文件路径:$SCAN_FILE_BIN"
	for file in $SCAN_DIR
	do
		find $file -type f -exec $SCAN_CMD \{\} \;>> $SCAN_FILE_BIN 2>/dev/null
	done
	echo "扫描完成,可利用以下命令后期对文件进行校验"
	echo "$SCAN_CMD -c $SCAN_FILE_BIN |grep -v 'OK$'"
}

clear
echo "##########################################"
echo "#                                                                                #"
echo "#        利用md5sum对文件进行校验                          #"
echo "#                                                                                #"
echo "##########################################"
echo "1: 全盘扫描"
echo "2: bin path扫描"
echo "3: EXIT"
# 选择扫描方式
read -p "Please input your choice:" method
case $method in 
1)
	scan_fall_disk;;
2)
	scan_bin;;
3)
        echo "you choce channel!" && exit 1;;
*)
	echo "input Error! Place input{1|2|3}" && exit 0;;
esac

三、测试

  • 扫描二进制可执行文件 由于可执行文件异常敏感,如果系统可能有将自己的程序放在可行性路径下,或替换原有二进制文件,对

    $PATH
    

    目录进行扫描

    img

    将wc 文件移动到其他路径,或按照其他程序,二进制文件有变化就可以检测出来

    img

  • 全盘扫描

    img

俄罗斯方块

#!/bin/bash
 
APP_NAME="${0##*[\\/]}"
APP_VERSION="1.0"
 
#颜色定义
iSumColor=7         #颜色总数
cRed=1              #红色
cGreen=2            #绿色
cYellow=3           #×××
cBlue=4             #蓝色
cFuchsia=5          #紫红色
cCyan=6             #青色(蓝绿色)
cWhite=7            #白色
 
#位置与大小
marginLeft=3            #边框左边距
marginTop=2         #边框上边距
((mapLeft=marginLeft+2))    #棋盘左边距
((mapTop=$marginTop+1))     #棋盘上边距
mapWidth=10         #棋盘宽度
mapHeight=15            #棋盘高度
 
#颜色设置
cBorder=$cGreen
cScore=$cFuchsia
cScoreValue=$cCyan
 
#控制信号
#游戏使用两个进程,一个用于接收输入,一个用于游戏流程和显示界面;
#当前者接收到上下左右等按键时,通过向后者发送signal的方式通知后者。
sigRotate=25        #向上键
sigLeft=26
sigRight=27
sigDown=28
sigAllDown=29       #空格键
sigExit=30
 
#方块定义,7大类19种样式
#前8位为方块坐标,后2位为方块刚出现的时候的位置
box0_0=(0 0 0 1 1 0 1 1 0 4)
 
box1_0=(0 1 1 1 2 1 3 1 0 3)
box1_1=(1 0 1 1 1 2 1 3 -1 3)
 
box2_0=(0 0 1 0 1 1 2 1 0 4)
box2_1=(0 1 0 2 1 0 1 1 0 3)
 
box3_0=(0 1 1 0 1 1 2 0 0 4)
box3_1=(0 0 0 1 1 1 1 2 0 4)
 
box4_0=(0 2 1 0 1 1 1 2 0 3)
box4_1=(0 1 1 1 2 1 2 2 0 3)
box4_2=(1 0 1 1 1 2 2 0 -1 3)
box4_3=(0 0 0 1 1 1 2 1 0 4)
 
box5_0=(0 0 1 0 1 1 1 2 0 3)
box5_1=(0 1 0 2 1 1 2 1 0 3)
box5_2=(1 0 1 1 1 2 2 2 -1 3)
box5_3=(0 1 1 1 2 0 2 1 0 4)
 
box6_0=(0 1 1 0 1 1 1 2 0 3)
box6_1=(0 1 1 1 1 2 2 1 0 3)
box6_2=(1 0 1 1 1 2 2 1 -1 3)
box6_3=(0 1 1 0 1 1 2 1 0 4)
 
iSumType=7          #方块类型总数
boxStyle=(1 2 2 2 4 4 4)    #各种方块旋转后可能的样式数目
 
iScoreEachLevel=50  #提升一个级别需要的分数
#运行时数据
sig=0           #接收到的signal
iScore=0        #总分
iLevel=0        #速度级
boxNext=()      #下一个方块
iboxNextColor=0     #下一个方块的颜色
iboxNextType=0      #下一个方块的种类
iboxNextStyle=0     #下一个方块的样式
boxCur=()       #当前方块的位置定义
iBoxCurColor=0      #当前方块的颜色
iBoxCurType=0       #当前方块的种类
iBoxCurStyle=0      #当前方块的样式
boxCurX=-1      #当前方块的x坐标位置
boxCurY=-1      #当前方块的y坐标位置
map=()          #棋盘图表
 
#初始化所有背景方块为-1, 表示没有方块
for ((i = 0; i < mapHeight * mapWidth; i++))
do
    map[$i]=-1
done
 
#接收输入的进程的主函数
function RunAsKeyReceiver()
{
    local pidDisplayer key aKey sig cESC sTTY
 
    pidDisplayer=$1
    aKey=(0 0 0)
 
    cESC=`echo -ne "\033"`
    cSpace=`echo -ne "\040"`
 
    #保存终端属性。在read -s读取终端键时,终端的属性会被暂时改变。
    #如果在read -s时程序被不幸杀掉,可能会导致终端混乱,
    #需要在程序退出时恢复终端属性。
    sTTY=`stty -g`
 
    #捕捉退出信号
    trap "MyExit;" INT QUIT
    trap "MyExitNoSub;" $sigExit
 
    #隐藏光标
    echo -ne "\033[?25l"
 
    while :
    do
        #读取输入。注-s不回显,-n读到一个字符立即返回
        read -s -n 1 key
 
        aKey[0]=${aKey[1]}
        aKey[1]=${aKey[2]}
        aKey[2]=$key
        sig=0
 
        #判断输入了何种键
        if [[ $key == $cESC && ${aKey[1]} == $cESC ]]
        then
            #ESC键
            MyExit
        elif [[ ${aKey[0]} == $cESC && ${aKey[1]} == "[" ]]
        then
            if [[ $key == "A" ]]; then sig=$sigRotate   #<向上键>
            elif [[ $key == "B" ]]; then sig=$sigDown   #<向下键>
            elif [[ $key == "D" ]]; then sig=$sigLeft   #<向左键>
            elif [[ $key == "C" ]]; then sig=$sigRight  #<向右键>
            fi
        elif [[ $key == "W" || $key == "w" ]]; then sig=$sigRotate  #W, w
        elif [[ $key == "S" || $key == "s" ]]; then sig=$sigDown    #S, s
        elif [[ $key == "A" || $key == "a" ]]; then sig=$sigLeft    #A, a
        elif [[ $key == "D" || $key == "d" ]]; then sig=$sigRight   #D, d
        elif [[ "[$key]" == "[]" ]]; then sig=$sigAllDown   #空格键
        elif [[ $key == "Q" || $key == "q" ]]           #Q, q
        then
            MyExit
        fi
 
        if [[ $sig != 0 ]]
        then
            #向另一进程发送消息
            kill -$sig $pidDisplayer
        fi
    done
}
 
#退出前的恢复
MyExitNoSub()
{
    local y
 
    #恢复终端属性
    stty $sTTY
    ((y = marginTop + mapHeight + 4))
 
    #显示光标
    echo -e "\033[?25h\033[${y};0H"
    exit
}
 
MyExit()
{
    #通知显示进程需要退出
    kill -$sigExit $pidDisplayer
 
    MyExitNoSub
}
 
#处理显示和游戏流程的主函数
RunAsDisplayer()
{
    local sigThis
    InitDraw
 
    #挂载各种信号的处理函数
    trap "sig=$sigRotate;" $sigRotate
    trap "sig=$sigLeft;" $sigLeft
    trap "sig=$sigRight;" $sigRight
    trap "sig=$sigDown;" $sigDown
    trap "sig=$sigAllDown;" $sigAllDown
    trap "ShowExit;" $sigExit
 
    while :
    do
        #根据当前的速度级iLevel不同,设定相应的循环的次数
        for ((i = 0; i < 21 - iLevel; i++))
        do
            sleep 0.02
            sigThis=$sig
            sig=0
 
            #根据sig变量判断是否接受到相应的信号
            if ((sigThis == sigRotate)); then BoxRotate;    #旋转
            elif ((sigThis == sigLeft)); then BoxLeft;  #左移一列
            elif ((sigThis == sigRight)); then BoxRight;    #右移一列
            elif ((sigThis == sigDown)); then BoxDown;  #下落一行
            elif ((sigThis == sigAllDown)); then BoxAllDown;    #下落到底
            fi
        done
        #kill -$sigDown $$
        BoxDown #下落一行
    done
}
 
#绘制当前方块,传第一个参数,0表示擦除当前方块,1表示绘制当前方块
DrawCurBox()
{
    local i x y bErase sBox
    bErase=$1
    if (( bErase == 0 ))
    then
        sBox="\040\040"     #用两个空格擦除
    else
        sBox="[]"
        echo -ne "\033[1m\033[3${iBoxCurColor}m\033[4${iBoxCurColor}m"
    fi
 
    for ((i = 0; i < 8; i += 2))
    do
        ((y = mapTop + 1 + ${boxCur[$i]} + boxCurY))
        ((x = mapLeft + 1 + 2 * (boxCurX + ${boxCur[$i + 1]})))
        echo -ne "\033[${y};${x}H${sBox}"
    done
    echo -ne "\033[0m"
}
 
#移动方块
#BoxMove(y, x), 测试是否可以把移动中的方块移到(y, x)的位置, 返回0则可以, 1不可以
BoxMove()
{
    local i x y xPos yPos
    yPos=$1
    xPos=$2
    for ((i = 0; i < 8; i += 2))
    do
        #方块相对于棋盘坐标
        ((y = yPos + ${boxCur[$i]}))
        ((x = xPos + ${boxCur[$i + 1]}))
 
        if (( y < 0 || y >= mapHeight || x < 0 || x >= mapWidth))
        then
            #撞到墙壁了
            return 1
        fi
 
        if (( ${map[y * mapWidth + x]} != -1 ))
        then
            #撞到其他已经存在的方块了
            return 1
        fi
    done
    return 0;
}
 
#将方块贴到棋盘上
Box2Map()
{
    local i j x y line
    #将当前移动中的方块贴到棋盘对应的区域
    for ((i = 0; i < 8; i += 2))
    do
        #计算方块相对于棋盘的坐标
        ((y = ${boxCur[$i]} + boxCurY))
        ((x = ${boxCur[$i + 1]} + boxCurX))
        map[y*mapWidth+x]=$iBoxCurColor #将方块颜色赋给地图
    done
 
    line=0
    for ((i = 0; i < mapHeight; i++))
    do
        for ((j = 0; j < mapWidth; j++))
        do
            #如果棋盘上有空隙,跳出循环
            [[ ${map[i*mapWidth+j]} -eq -1 ]] && break
        done
 
        [ $j -lt $mapWidth ] && continue
        #说明当前行可消去,可消去行数加一
        (( line++ ))
 
        #第i行可被消除,将0行至第i-1行全部下移一行,从第i-1行开始移动
        for ((j = i*mapWidth-1; j >= 0; j--))
        do
            ((x = j + mapWidth))
            map[$x]=${map[$j]}
        done
 
        #因为下移一行,第0行置空
        for ((i = 0; i < mapWidth; i++))
        do
            map[$i]=-1
        done
    done
 
    [ $line -eq 0 ] && return
 
    #根据消去的行数line计算分数和速度级
    ((x = marginLeft + mapWidth * 2 + 7))
    ((y = marginTop + 11))
    ((iScore += line * 2 - 1))
    #显示新的分数
    echo -ne "\033[1m\033[3${cScoreValue}m\033[${y};${x}H${iScore}         "
    if ((iScore % iScoreEachLevel < line * 2 - 1))
    then
        if ((iLevel < 20))
        then
            ((iLevel++))
            ((y = marginTop + 14))
            #显示新的速度级
            echo -ne "\033[3${cScoreValue}m\033[${y};${x}H${iLevel}        "
        fi
    fi
    echo -ne "\033[0m"
 
    #重新显示背景方块
    for ((i = 0; i < mapHeight; i++))
    do
        #棋盘相对于屏幕的坐标
        ((y = i + mapTop + 1))
        ((x = mapLeft + 1))
        echo -ne "\033[${y};${x}H"
        for ((j = 0; j < mapWidth; j++))
        do
            ((tmp = i * mapWidth + j))
            if ((${map[$tmp]} == -1))
            then
                echo -ne "  "
            else
                echo -ne "\033[1m\033[3${map[$tmp]}m\033[4${map[$tmp]}m[]\033[0m"
            fi
        done
    done
}
 
#左移一格
BoxLeft()
{
    local x
    ((x = boxCurX - 1))
    if BoxMove $boxCurY $x
    then
        DrawCurBox 0
        ((boxCurX = x))
        DrawCurBox 1
    fi
}
 
#右移一格
BoxRight()
{
    local x
    ((x = boxCurX + 1))
    if BoxMove $boxCurY $x
    then
        DrawCurBox 0
        ((boxCurX = x))
        DrawCurBox 1
    fi
}
 
#向下移一格
BoxDown()
{
    local y
    ((y = boxCurY + 1)) #新的y坐标
    if BoxMove $y $boxCurX  #测试是否可以下落一行
    then
        DrawCurBox 0    #将旧的方块抹去
        ((boxCurY = y))
        DrawCurBox 1    #显示新的下落后方块
    else
        #走到这儿, 如果不能下落了
        Box2Map     #将当前移动中的方块贴到背景方块中
        CreateBox   #产生新的方块
    fi
}
 
#下落到底
BoxAllDown()
{
    local y iDown
 
    #计算能够下落的行数
    iDown=0
    (( y = boxCurY + 1 ))
    while BoxMove $y $boxCurX
    do
        (( y++ ))
        (( iDown++ ))
    done
 
    DrawCurBox 0    #将旧的方块抹去
    ((boxCurY += iDown))
    DrawCurBox 1    #显示新的下落后的方块
    Box2Map     #将当前移动中的方块贴到背景方块中
    CreateBox   #产生新的方块
}
 
#翻转
BoxRotate()
{
    [ ${boxStyle[$iBoxCurType]} -eq 1 ] && return
    ((rotateStyle = (iBoxCurStyle + 1) % ${boxStyle[$iBoxCurType]}))
    #将当前方块保存到boxTmp
    boxTmp=( `eval 'echo ${boxCur[@]}'` )
    boxCur=( `eval 'echo ${box'$iBoxCurType'_'$rotateStyle'[@]}'` )
 
    if BoxMove $boxCurY $boxCurX    #测试旋转后是否有空间放的下
    then
        #抹去旧的方块
        boxCur=( `eval 'echo ${boxTmp[@]}'` )
        DrawCurBox 0
 
        boxCur=( `eval 'echo ${box'$iBoxCurType'_'$rotateStyle'[@]}'` )
        DrawCurBox 1
        iBoxCurStyle=$rotateStyle
    else
        #不能旋转,还是继续使用老的样式
        boxCur=( `eval 'echo ${boxTmp[@]}'` )
    fi
}
 
#准备下一个方块
PrepareNextBox()
{
    local i x y
    #清除右边预显示的方块
    if (( ${#boxNext[@]} != 0 )); then
        for ((i = 0; i < 8; i += 2))
        do
            ((y = marginTop + 1 + ${boxNext[$i]}))
            ((x = marginLeft + 2 * mapWidth + 7 + 2 * ${boxNext[$i + 1]}))
            echo -ne "\033[${y};${x}H\040\040"
        done
    fi
 
    #随机生成预显式方块
    (( iBoxNextType = RANDOM % iSumType ))
    (( iBoxNextStyle = RANDOM % ${boxStyle[$iBoxNextType]} ))
    (( iBoxNextColor = RANDOM % $iSumColor + 1 ))
 
    boxNext=( `eval 'echo ${box'$iBoxNextType'_'$iBoxNextStyle'[@]}'` )
 
    #显示右边预显示的方块
    echo -ne "\033[1m\033[3${iBoxNextColor}m\033[4${iBoxNextColor}m"
    for ((i = 0; i < 8; i += 2))
    do
        ((y = marginTop + 1 + ${boxNext[$i]}))
        ((x = marginLeft + 2 * mapWidth + 7 + 2 * ${boxNext[$i + 1]}))
        echo -ne "\033[${y};${x}H[]"
    done
 
    echo -ne "\033[0m"
 
}
 
#显示新方块
CreateBox()
{
    if (( ${#boxCur[@]} == 0 )); then
        #当前方块不存在
        (( iBoxCurType = RANDOM % iSumType ))
        (( iBoxCurStyle = RANDOM % ${boxStyle[$iBoxCurType]} ))
        (( iBoxCurColor = RANDOM % $iSumColor + 1 ))
    else
        #当前方块已存在, 将下一个方块赋给当前方块
        iBoxCurType=$iBoxNextType;
        iBoxCurStyle=$iBoxNextStyle;
        iBoxCurColor=$iBoxNextColor
    fi
 
    #当前方块数组
    boxCur=( `eval 'echo ${box'$iBoxCurType'_'$iBoxCurStyle'[@]}'` )
    #初始化方块起始坐标
    boxCurY=boxCur[8];
    boxCurX=boxCur[9];
 
    DrawCurBox 1        #绘制当前方块
    if ! BoxMove $boxCurY $boxCurX
    then
        kill -$sigExit $PPID
        ShowExit
    fi
 
    PrepareNextBox
 
}
 
#绘制边框
DrawBorder()
{
    clear
 
    local i y x1 x2
    #显示边框
    echo -ne "\033[1m\033[3${cBorder}m\033[4${cBorder}m"
 
    ((x1 = marginLeft + 1))             #左边框x坐标
    ((x2 = x1 + 2 + mapWidth * 2))          #右边框x坐标
    for ((i = 0; i < mapHeight; i++))
    do
        ((y = i + marginTop + 2))
        echo -ne "\033[${y};${x1}H||"       #绘制左边框
        echo -ne "\033[${y};${x2}H||"       #绘制右边框
    done
 
    ((x1 = marginTop + mapHeight + 2))
    for ((i = 0; i < mapWidth + 2; i++))
    do
        ((y = i * 2 + marginLeft + 1))
        echo -ne "\033[${mapTop};${y}H=="   #绘制上边框
        echo -ne "\033[${x1};${y}H=="       #绘制下边框
    done
    echo -ne "\033[0m"
 
    #显示"Score"和"Level"字样
    echo -ne "\033[1m"
    ((y = marginLeft + mapWidth * 2 + 7))
    ((x1 = marginTop + 10))
    echo -ne "\033[3${cScore}m\033[${x1};${y}HScore"
    ((x1 = marginTop + 11))
    echo -ne "\033[3${cScoreValue}m\033[${x1};${y}H${iScore}"
    ((x1 = marginTop + 13))
    echo -ne "\033[3${cScore}m\033[${x1};${y}HLevel"
    ((x1 = marginTop + 14))
    echo -ne "\033[3${cScoreValue}m\033[${x1};${y}H${iLevel}"
    echo -ne "\033[0m"
}
 
InitDraw()
{
    clear           #清屏
    DrawBorder      #绘制边框
    CreateBox       #创建方块
}
 
#退出时显示GameOVer!
ShowExit()
{
    local y
    ((y = mapHeight + mapTop + 3))
    echo -e "\033[${y};1HGameOver!\033[0m"
    exit
}
 
#游戏主程序在这儿开始.
if [[ "$1" == "--version" ]]; then
    echo "$APP_NAME $APP_VERSION"
elif [[ "$1" == "--show" ]]; then
    #当发现具有参数--show时,运行显示函数
    RunAsDisplayer
else
    bash $0 --show& #以参数--show将本程序再运行一遍
    RunAsKeyReceiver $! #以上一行产生的进程的进程号作为参数
fi
 
keytest.sh
 
#!/bin/bash
 
GetKey()
{
    aKey=(0 0 0) #定义一个数组来保存3个按键
 
    cESC=`echo -ne "\033"`
    cSpace=`echo -ne "\040"`
 
    while :
    do
        read -s -n 1 key  #读取一个字符,将读取到的字符保存在key中
        #echo $key
        #echo XXX 
 
        aKey[0]=${aKey[1]} #第一个按键
        aKey[1]=${aKey[2]} #第二个按键
        aKey[2]=$key        #第三个按键
 
        if [[ $key == $cESC && ${aKey[1]} == $cESC ]]
        then
            MyExit
        elif [[ ${aKey[0]} == $cESC && ${aKey[1]} == "[" ]]
        then
            if [[ $key == "A" ]]; then echo KEYUP
            elif [[ $key == "B" ]]; then echo KEYDOWN
            elif [[ $key == "D" ]]; then echo KEYLEFT
            elif [[ $key == "C" ]]; then echo KEYRIGHT
            fi
        fi
    done
}
 
GetKey
 
draw.sh
 
#!/bin/bash
 
#位置与大小
marginLeft=8            #边框左边距
marginTop=6         #边框上边距
((mapLeft=marginLeft+2))    #棋盘左边距
((mapTop=$marginTop+1))     #棋盘上边距
mapWidth=10         #棋盘宽度
mapHeight=15            #棋盘高度
 
#方块定义,7大类19种样式
#前8位为方块坐标,后2位为方块刚出现的时候的位置
box0_0=(0 0 0 1 1 0 1 1 0 4)
 
box1_0=(0 1 1 1 2 1 3 1 0 3)
box1_1=(1 0 1 1 1 2 1 3 -1 3)
 
box2_0=(0 0 1 0 1 1 2 1 0 4)
box2_1=(0 1 0 2 1 0 1 1 0 3)
 
box3_0=(0 1 1 0 1 1 2 0 0 4)
box3_1=(0 0 0 1 1 1 1 2 0 4)
 
box4_0=(0 2 1 0 1 1 1 2 0 3)
box4_1=(0 1 1 1 2 1 2 2 0 3)
box4_2=(1 0 1 1 1 2 2 0 -1 3)
box4_3=(0 0 0 1 1 1 2 1 0 4)
 
box5_0=(0 0 1 0 1 1 1 2 0 3)
box5_1=(0 1 0 2 1 1 2 1 0 3)
box5_2=(1 0 1 1 1 2 2 2 -1 3)
box5_3=(0 1 1 1 2 0 2 1 0 4)
 
box6_0=(0 1 1 0 1 1 1 2 0 3)
box6_1=(0 1 1 1 1 2 2 1 0 3)
box6_2=(1 0 1 1 1 2 2 1 -1 3)
box6_3=(0 1 1 0 1 1 2 1 0 4)
 
#绘制边框
DrawBorder()
{
    clear
 
    local i y x1 x2
    #显示边框
    echo -ne "\033[1m\033[32m\033[42m"
 
    ((x1 = marginLeft + 1))             #左边框x坐标
    ((x2 = x1 + 2 + mapWidth * 2))          #右边框x坐标
    for ((i = 0; i < mapHeight; i++))
    do
        ((y = i + marginTop + 2))
        echo -ne "\033[${y};${x1}H||"       #绘制左边框
        echo -ne "\033[${y};${x2}H||"       #绘制右边框
    done
 
    ((x1 = marginTop + mapHeight + 2))
    for ((i = 0; i < mapWidth + 2; i++))
    do
        ((y = i * 2 + marginLeft + 1))
        echo -ne "\033[${mapTop};${y}H=="   #绘制上边框
        echo -ne "\033[${x1};${y}H=="       #绘制下边框
    done
    echo -ne "\033[0m"
}
 
DrawBox()
{
    local i x y xPos yPos
    yPos=${box0_0[8]}
    xPos=${box0_0[9]}
    echo -ne "\033[1m\033[35m\033[45m"
    for ((i = 0; i < 8; i += 2))
    do
        (( y = mapTop + 1 + ${box0_0[$i]} + yPos ))
        (( x = mapLeft + 1 + 2 * (${box0_0[$i + 1]} + xPos) ))
        echo -ne "\033[${y};${x}H[]"
    done
    echo -ne "\033[0m"
}
 
InitDraw()
{
    clear           #清屏
    DrawBorder      #绘制边框
    DrawBox
    while :
    do
        sleep 1
    done
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/153228.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【RabbitMQ】安装、启动、配置、测试一条龙

一、基本环境安装配置 1.英文RabbitMQ是基于erlang开发的所以需要erlang环境,点击以下链接下载安装 Downloads - Erlang/OTP 2.官网下载RabbitMQ安装包并安装 Installing on Windows — RabbitMQ 3.配置erlang本地环境变量(和JAVAHOME类似) 4.cmd查看erlang版本 5.点击以下…

自己看的操作系统

计算机网络冯诺依曼体系进程线程内核和虚拟内存os管理线程冯诺依曼体系 计算机五大组成&#xff1a;输入设备、输出设备、控制器、运算器、存储器 进程线程 这些应用都是进程 进程相当于一个菜谱&#xff0c;读取到内存中去使用。 电脑一时间能运行很多进程。 进程中为什么要…

excel函数技巧:MAX在数字查找中的应用妙招

大家都知道VLOOKUP可以按给定的内容去匹配到我们所需的数据&#xff0c;正因为如此&#xff0c;它在函数界有了很大的名气。但是今天要分享的这三个示例&#xff0c;如果使用VLOOKUP去匹配数据的话&#xff0c;就有些麻烦了。就在VLOOKUP头疼不已的时候&#xff0c;MAX函数二话…

2022 年度总结

1、CSDN 年度总结 2022年的粉丝涨幅比较明显竟然超过了之前几年的总和&#xff0c;这是比较意外的。应该是因为今年研究了一些云原生、元宇宙的原因&#xff0c;方向比努力真的重要的多。 1500的阅读确实没想到~~~说明低头一族还是没白当 涨粉稍微明细&#xff0c;不过还需…

English Learning - L1-11 时态 + 情态动词 2023.1.9 周一

English Learning - L1-11 时态 情态动词 2023.1.9 周一8 时态8.4 完成进行时&#xff08;一&#xff09;现在完成进行时核心思维&#xff1a;动作开始于现在之前&#xff0c;并有限地持续下去&#xff0c;动作到目前为止尚未完成1. 动作从过去某时开始一直持续到现在并可能继…

【Python】如何使用python将一个py文件变成一个软件?

系列文章目录 这个系列文章将写一些python中好玩的小技巧。 第一章 使用Python 做一个软件 目录 系列文章目录 前言 一、第一步&#xff1a;写好文件 二、第二步&#xff1a;生成程序 1.安装库 2.使用安装的库进行转化 总结 前言 本文重点说如何将py文件转化为exe文件…

回溯法--符号三角形(杂记)

回溯法说来简单&#xff0c;写起来难&#xff0c;真的是要愁死。回溯法有两种模板--子集树、排列树5.4符号三角形--dfs计算多少个满足条件的符号三角形&#xff0c;同号下面为“”&#xff0c;异号下面为“-”。根据异或的规则我们令“”0&#xff0c;“-”1&#xff0c;(异或的…

postgresql 启用ssl安全连接方式

SSL的验证流程 利用openssl环境自制证书 CA 证书签发 创建私钥ca.key,使用des3算法,有效期2048天 openssl genrsa -des3 -out ca.key 2048生成根CA证书请求&#xff08;.csr&#xff09; openssl req -new -key ca.key -out ca.csr -subj "/CCN/STGuangDong/LGuangZhou…

Cloudflare免费版不支持cname解析解决办法

最近调整CDN&#xff0c;使用云盾CDN的话基本上节点都在国内&#xff0c;国外访问就比较难了&#xff0c;虽然我们的站国外用户基本没有&#xff0c;但作为一个有大抱负的站长&#xff0c;眼界必须得宽&#xff0c;必须得支持国外访问才行&#xff01;说起国外免费CDN&#xff…

iOS开发之Code:-402653103,Code:5

问题一&#xff1a;Code&#xff1a;-402653103 Demo中添加了第三方库&#xff0c;然后运行Demo时&#xff0c;总是运行不起来&#xff0c;现象如下&#xff1a; 遇到这种问题常见的几种方式&#xff1a; 方式一&#xff1a;command shift K&#xff0c;清理Xcode缓存&…

常用的字符串与内存操作函数(1)

Tips 1. 2. 3. 在进行数值计算的时候&#xff0c;补码能算对&#xff0c;因此计算机里面放的都是补码&#xff0c;运算的对象都是补码 但是与真实数值吻合的是原码&#xff0c;因此打印&#xff0c;求值等都要转化为原码 4. for (exp1 ; exp2 ; exp3)&#xff0c;是先…

从0到1完成一个Vue后台管理项目(十九、地图区域样式设置、区域文字和立体设置)

往期 从0到1完成一个Vue后台管理项目&#xff08;一、创建项目&#xff09; 从0到1完成一个Vue后台管理项目&#xff08;二、使用element-ui&#xff09; 从0到1完成一个Vue后台管理项目&#xff08;三、使用SCSS/LESS&#xff0c;安装图标库&#xff09; 从0到1完成一个Vu…

上半年要写的博客文章25

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注…

分享86个NET源码,总有一款适合您

NET源码 分享86个NET源码&#xff0c;总有一款适合您 链接&#xff1a;https://pan.baidu.com/s/1JOY-9pJIM7sUhafxupMaZw?pwdfs2y 提取码&#xff1a;fs2y 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c;大家下载…

Blender里的三种绑定:(一)主从绑定

文章目录Blender里的三种绑定.主从绑定.进行物体绑定.进行顶点绑定.解除绑定.保持变换.无反向.进行晶格绑定.Blender里的三种绑定. 1 Blender中一共有三种绑定模式&#xff0c;分别是 主从绑定&#xff0c;约束&#xff0c;骨骼 主从绑定. 1 主从绑定即父子关系&#xff0c;…

【Spark常用算子合集】一文搞定spark中的常用转换与行动算子

&#x1f680; 作者 &#xff1a;“大数据小禅” &#x1f680;文章简介&#xff1a;本篇文章属于Spark系列文章&#xff0c;专栏将会记录从spark基础到进阶的内容 &#x1f680; 内容涉及到Spark的入门集群搭建&#xff0c;核心组件&#xff0c;RDD&#xff0c;算子的使用&…

【数据结构与算法】——第六章:图

文章目录1、图的定义1.1 图的其他定义1.2 图的顶点与边之间的关系1.3 连通图相关术语2、图的存储结构2.1 邻接矩阵2.2 邻接表3、图的遍历3.1 深度优先遍历3.2 广度优先遍历4、最小生成树4.1 普利姆算法(Prim)4.2 克鲁斯卡尔(kruskal)5、最短路径5.1 迪杰斯特拉(Dijkstra)算法5.…

Sentinel限流-@SentinelResource注解配置

SentinelResource 配置-上 &#xff08;按资源名配置限流规则&#xff09; 1&#xff09; Sentinel 控制台配置流控规则&#xff1a; 2&#xff09;java 代码&#xff1a; GetMapping("/byResource")SentinelResource(value "byResource", blockHandler …

Django项目——通过APIView实现API访问

前提 该文章在已有项目的基础上进行修改 https://blog.csdn.net/qq_38122800/article/details/128583379?spm1001.2014.3001.5502 1、配置序列化器 序列化器包含序列化和反序列化两个过程,简单点理解就是 序列化 : 将从数据库中查的数据变为前端页面可以接受的json数据 反…

Odoo 16 企业版手册 - 库存管理之重订货规则

重订货规则 在Odoo 库存模块中&#xff0c;您可以配置一组规则&#xff0c;帮助您确保库存永远不会用完。Odoo将尝试使用重订货规则在您的库存中保持至少最低数量的产品。让我们看看此功能在Odoo 16中是如何工作的。为此&#xff0c;您可以从库存模块中选择一个可存储的产品。 …