shell脚本练习2023年下岗版

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
}
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极客云曦

你的鼓励就是我最大的创作动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值