这里包括shell变量,shell条件判断,shell多进程,Fd和命名管道

目录

简介

shell条件测试

判断某一个条件是不是城里的, 格式有三种,分别是 1. test 2. [ ] 3. [[ ]] 分种类有三类,以下三类

1. 文件测试

#!/usr/bin/bash
back_dir=/var/mysql_back
#检查这个目录是否存在,如果不存在,则创建
if ! test -d $back_dir;then
        mkdir -p $back_dir
fi


[]和使用test是一致的,注意使用[]的空格

  1. -e filename 如果 filename 存在,则为真[[ -e /var/log/syslog ]]
  2. -d filename 如果 filename 为目录,则为真[[ -d /tmp/mydir ]]
  3. -f filename 如果 filename 为常规文件,则为真[[ -f /usr/bin/grep ]]
  4. -L filename 如果 filename 为符号链接,则为真[[ -L /usr/bin/grep ]]
  5. -r filename 如果 filename 对于当前用户可读,则为真[[ -r /var/log/syslog ]]
  6. -w filename 如果 filename 可写,则为真[[ -w /var/mytmp.txt ]]
  7. -x filename 如果 filename 可执行,则为真[[ -L /usr/bin/grep ]]
  8. filename1 -nt filename2 如果 filename1 比 filename2 新,则为真[[ /tmp/install/etc/services -nt /etc/services ]]
  9. filename1 -ot filename2 如果 filename1 比 filename2 旧,则为真[[ /boot/bzImage -ot arch/i386/boot/bzImage ]]

    filePath="/root/test.txt"
    if [[ -e $filePath ]]
    then
     echo "file is exist"
    else
     echo "file is not exist"
    fi
    

2.数字比较判断

    num1 -eq num2   等于          [[ 3 -eq $mynum ]]
    num1 -ne num2   不等于     [[ 3 -ne $mynum ]]
    num1 -lt num2   小于          [[ 3 -lt $mynum ]]
    num1 -le num2   小于或等于   [[ 3 -le $mynum ]]
    num1 -gt num2   大于          [[ 3 -gt $mynum ]]
    num1 -ge num2   大于或等于   [[ 3 -ge $mynum ]]
a=10
b=20
if [[ $a -eq $b ]];then
echo "$a -eq $b : a 等于 b"
else
echo "$a -eq $b: a 不等于 b"
fi

3.字符串比较判断

注意字符串要加双引号

    -z string           如果 string 长度为零,则为真[[ -z $myvar ]]
    -n string           如果 string 长度非零,则为真[[ -n $myvar ]]
    string1 == string2  如果 string1 与 string2 相同,则为真[[ $myvar == one two three ]]string1 != string2  如果 string1 与 string2 不同,则为真[[ $myvar != one two three ]]
#!/usr/bin/bash
#注意字符串要加双引号
str1="i am xiaoming"
str2="i am xiaoqiang"
if [[ $str1 == $str2 ]]
then
echo "咦!我俩咋相同"
else
echo "咦!我俩咋不一样"
fi

shell条件测试实例

shell1.sh

#!/usr/bin/bash
grep 'cat $1' *#从所有文件中找到含有字符串cat $1的东西
#判断是否有参数
if [ $# -eq 0 ];then
        echo "no value can not exe `basename $0` file"
fi
#检查是不是文件
if [ !-f $1];then
        echo "error file type"
        exit
fi

for ip in `cat $1`
do
        ping -c1 $ip&> /dev/null
        if [ $? -eq 0 ]
        then
                echo "$ip is up"
        else
                echo "$ip is down"
        fi
done

shell2.sh

输入一个用户名,如果存在,则提示退出,如果不存在则创建后提示成功

#!/usr/bin/bash

grep 'cat $1' *#从所有文件中找到含有字符串cat $1的东西
read -p "请输入用户名:" user
if id $user&.>/dev/null; then
        echo "$user is already exists"
        exit
else
        useradd $user
        if [ $? -eq 0 ];then
                echo "$user creat success"
        fi
fi 

shell3.sh

磁盘报警及计划任务

#!/usr/bin/bash
df -h |grep  '/$'
100.0G     53.2G     46.8G  53% /
df -h |grep  '/$' | awk '{print $(NF-1)}'
53%
df -h |grep  '/$' | awk '{print $(NF-1)}' | awk -F"%" '{print $1}'#去掉百分号
53

disk_mem=`df -h |grep  '/$' | awk '{print $(NF-1)}' | awk -F"%" '{print $1}'`# set value
mail_user=alice
if [ $disk_mem -ge 90 ];then
        #send a mail to user by title named disk war...
        echo "`date+%F-%H` disk : ${disk_mem}%" |mail -s "disk war..." $mail_user
fi

这里可以添加计划任务 :每隔五分钟执行一次任务 crontab -e来执行 添加 */5 * * * * /bin/bash shell3.sh

shell4.sh

内存报警及计划任务

获取内存值得使用情况,这里使用到了bash -vx可以对脚本进行输出调试

#!/usr/bin/bash
#^代表行首,$代表行尾,表示以Mem开头
free -m |grep  '^Mem'
#1               2           3           4             5
Mem:             8064        5276        2788           0           0

free -m | grep '^Mem:' | awk '{print $3}'
5298

mem1=`free -m | grep '^Mem:' | awk '{print $3}'`
mem2=`free -m | grep '^Mem:' | awk '{print $2}'`
mem3=$(({mem1}*100/mem2))
echo "当前占用${mem3}%"
war_file=/bin/war.txt
mail_user=alice
rm -rf $war_file #判断是否有残留
if [ $mem3 -ge 80 ];then
    echo "`date+%F-%H` mem : ${mem3}%" |mail -s "disk war..." $mail_user
fi
if (( $mem3>80));then
    echo "`date+%F-%H` mem : ${mem3}%" > $war_file
fi
#判断文件是否存在
if [ -f $war_file ];then
        mail -s "disk war..." $mail_user < $war_file
        rm -rf $war_file
fi

shell模式匹配 case

语法结构

case 变量 in

mode_1)
        commond1
        ;;
mode_2)
        commond2
        ;;
mode_3)
        commond3
        ;;
*)#相当于c语言中的default
        commond
esac

shell模式匹配for

2.1、循环遍历传入进来的参数

  for x in $@
  do
  echo number $x
  done

2.2、遍历内存中的数组

  arr=("one" "two" 123 456)
  for x in ${arr[@]}
  do
  echo number $x
  done

2.3、修改IFS=\n,将cat的结果变成数组,然后再for

  #!/bin/bash
  # 由于cat 是以\n来区分行,所以需要修改IFS
  oldIFS=$IFS
  IFS="\\n"

  # 将cat得到的文件内容,收集起来,加上()转化为数组
  catLines=(`cat /etc/hosts`)
  IFS=$oldIFS
  for line in ${catLines[*]}
  do
      echo $line
  done

2.4、遍历文件夹下的文件

  #!/bin/bash
  # 先收集成数组,这样只有文件名
  catLines=($(ls /root))
  for line in ${catLines[*]}
  do
      echo $line
  done

  # 直接读,这样line是完整路径
  for line in /root/*
  do
      echo $line
  done

shell模式判断实例

shell1.sh

#!/usr/bin/bash
#delet user
#首先学习检测一个输入是否为一个命令
command -v ls
alias ls='_bbf ls --color=auto'

read -p "input a username: " user
id $user &>/dev/null
if [$? -ne 0 ];then
        echo "no such user:$user"
        exit 1 #退出返回值为
fi
read -p "sure?{y/n}:" action
case $action in
"y"|"yes"|"Y")
        userdel -r $user
        echo "$user is delet!"
       ;;
"no")
        echo "good"
        : #返回为真,相当于ture命令
*)
        echo "bad"
esac

shell2.sh 跳板机,堡垒主机

跳板机(Jump Server),也称堡垒机,是一类可作为跳板批量操作远程设备的网络设备,跳板机最核心的功能是以本机作为跳板来操作远程设备,较为普遍地是通过ssh协议实现远程管理,使用单位一般会自己开发或选择性地使用以下自动化运维工具:

生产环境不建议root权限登录 一般生产环境有两个限制: 1:不允许直接连接 2:不允许root用户账户登录

远程登录一般为user登录,登录方式为密码账户或者密钥登录 将一下脚本放入 当前用户的.bash_profile里面 在最后一行加入 shell2.sh脚本的全路径

#!/usr/bin/bash
#jumpserver
trap "" HUP INT OUIT TSTP #用来屏蔽系统的中断信号,什么也不执行,防止从脚本中跳出来,屏蔽退出命令
web1=192.168.0.1
web2=192.168.0.2
web3=192.168.0.3
#函数
menu(){
cat <<-EOF
        +-------------------------------+
        |       1. web1                 |
        |       2. web2                 |
        |       3. web3                 |
        +-------------------------------+
EOF
}
while :
do
        clear
        menu 

        echo -e "\e[1;32mimput number: \e[0m"#换行输出绿色打印信息 input number:,-en是不换行的写法
        read num    
        #or read -p "input number: " num
        case $num in
        1)
                ssh alice@$web1
                ;;
        2)
                ssh alice@$web2
                ;;
        3)
                ssh alice@$web3
                ;;
        " ")
                ;;
        *)
                echo "input error "
                break
done

shell3.sh for循环的实现ping主机1

#!/usr/bin/bash
> a.txt #重定向 
for i in {2...254} #or for i in `cat ip.txt`     #这里要执行cat ip.txt,所以要执行``或者${}

do
        {
        ip=192.168.0.$i
        ping -c1 -W.1 $ip&> /dev/null   #-c1 ping一次,-W.1等待0.1s
        if [ $? -eq 0 ]
        then
                echo "$ip is up"|tee -a ip.txt #usr tee type creat a file to record ping history
        else
                echo "$ip is down"
        fi
        }&      # 在(子shell)后台执行
done
wait    #等待前面所有后台进程结束
echo "finish"

任何程序或者脚本,都可以在前面加个time来统计执行的时间 time /shell3.sh

shell4.sh for循环的实现创建用户2

#!/usr/bin/bash
while :
do
read -p "enter prefix & passwod & num" prefix pass num
printf "user information:
------------------------
prefix:$prefix
pass:$pass
num:$num
------------------------
"
read -p "are you sure ?:" action
#此处判断是否确认输入
if [ "$action"="y"];then
        break

fi
done


for i in `seq -w $num`#等位补齐
do
        user=$prefix$i
        id $user &>/dev/null
        if [ $? -eq 0 ];then #检测用户是否存在
                echo "can not create $user ,already exists"
        else
                useradd $user
                echo "pass" |passwd --stdin &user &>/dev/null
                if [ $? -eq 0];then
                        echo "creat $user success"
                fi
        fi
done
echo "create user"

shell5.sh for循环的实现文件中批量创建用户3

user.txt
a 123
b 456
d 789
#!/usr/bin/bash
#是否有输入参数
if [ $# -eq 0];then
        echo "nu value can not use: `basename $0` file"
        exit 1
fi
#检查类型
if [ ! -f $1];then
        echo "type wrong"
        exit 2
fi
#希望for处理文件按回车分割,而不是空格或tab空格
#但是for确实是这样--空格分割或tab空格
#所以要重新定义分隔符
#IFS内部字段分隔符
#IFS=$'\n'
#应增加以下两行 
#IFS='
#'
for line in `cat $1` #每一行,每一行取(错误写法)
do      
        #判断长度是否为0,这里for会自动筛选,则不需要这个
        if [ ${#line} -eq 0 ];then
                continue #break是跳出循环,continue是结束本次循环
        fi
        user= `echo "$line" |awk '{print $1}'`
        pass= `echo "$line" |awk '{print $2}'`
        id $user &>/dev/null
        if [ $? -eq 0 ];then #检测用户是否存在
                echo "can not create $user ,already exists"
        else
                useradd $user
                echo "pass" |passwd --stdin &user &>/dev/null
                if [ $? -eq 0];then
                        echo "creat $user success"
                fi
        fi
done

shell6.sh for循环的实现文件中批量创建用户3

#!/usr/bin/bash
#重定向,相当于删除原有存在的
#>ok.txt
#>fail.txt
read -p "please enter a new password" pass
for ip in `cat ip.txt`     #这里要执行cat ip.txt,所以要执行``或者$()

do
        {
        
        ping -c1 -W1 $ip&> /dev/null   #-c1 ping一次,-W1等待1s
        if [ $? -eq 0 ]
        then
                ssh $ip "echo $pass |passwd --stdin root"
                if [ $? -eq 0];then

                        echo "$ip is up"|tee -a ok_`date +%F`.txt #usr tee type creat a file to record ping history
                else
                        echo "$ip is down" >> fail_`date +%F`.txt #追加,不替代
                fi
        else
                echo "$ip is down" >>fail_`date +%F`.txt
        fi
        }&      # 在(子shell)后台执行
done
wait    #等待前面所有后台进程结束
echo "finish"

shell7.sh for实现ssh批量创建用户3

#!/usr/bin/bash
#重定向,相当于删除原有存在的
#>ok.txt
#>fail.txt
read -p "please enter a new password" pass
for ip in `cat ip.txt`     #这里要执行cat ip.txt,所以要执行``或者$()

do
        {
        
        ping -c1 -W1 $ip&> /dev/null   #-c1 ping一次,-W1等待1s
        if [ $? -eq 0 ]
        then
                #sed -ri '/^#UseDNS/cUseDNS no ' /etc/ssh/sshd_config #从/etc/ssh/sshd_config文件中,通过sed -ri查找 ,/^#UseDNS搜索以#UseDNS开头, /c替换为UseDNS
                #ssh $ip "echo $pass |passwd --stdin root"
                ssh $ip "sed -ri '/^#UseDNS/cUseDNS no ' /etc/ssh/sshd_config"
                #if [ $? -eq 0];then

                #        echo "$ip is up"|tee -a ok_`date +%F`.txt #usr tee type creat a file to record ping history
                #else
                #        echo "$ip is down" >> fail_`date +%F`.txt
                #fi
        else
                #echo "$ip is down" >>fail_`date +%F`.txt
        fi
        }&      # 在(子shell)后台执行
done
wait    #等待前面所有后台进程结束
echo "finish"

grep 'DNS' /ect.ssh_config #在某个文件中查找DNS并打印所得行

while应用,非常适合逐行处理文件!!!

  1. 普通的循环控制

    #!/bin/bash
    while [[ i -lt 10 ]]
    do
      echo $i
      i=$[i + 1]
    done
    
  2. 读取文件的每一行

    #!/bin/bash
    cat $1| while read hostLine
    do
      # 将hostLine转化为数组,第一个是ip,第二个是机器名称,第三个是密码
      # 如果hostLine分隔符是IFS默认的分隔符一种' ' 、 tab ,则可以直接下面这种方式切割
      ipArr=($hostLine)
    
      # 如果hostLine分隔符是",",要么临时修改IFS为",",要么将hostLine分隔符替换为' '
      # ipArr=(${hostLine//,/' '})
    
      IP=${ipArr[0]}
      NAME=${ipArr[1]}
      PASSWD=${ipArr[2]}
      echo "ip是:$IP  hostname是:$NAME  密码是:$PASSWD"
    done
    
  3. 普通的循环控制

    #!/bin/bash
    while : #:冒号返回为真
    do
      echo $i
      i=$[i + 1]
    done
    

shell1.sh create user

#!/usr/bin/bash
# 读取user.txt文件,创建账号,其中user是读的一行,因为read是以换行符为结束
while read user
do
        #判断用户是否存在
        id $user &>/dev/null
        if [ $? -eq 0];then
                echo "user already exists"
        else
                useradd $user
                if [ $? -eq 0 ];then

                        echo "$user ok"
                else
                        echo "bad"
                fi
        fi

done < user .txt #输入重定向

shell2.sh 探索while的字段分隔符定义

#!/usr/bin/bash
# 读取user.txt文件,创建账号,其中line是读的一行,因为read是以换行符为结束
while read line
do
        if [ ${#line} -eq 0 ];then
                echo    "---------------"
                continue

        fi
        #判断用户是否存在
        user =`echo $line|awk '{print $1}' `
        pass =`echo $line|awk '{print $2}' `
        id $user &>/dev/null
        if [ $? -eq 0];then
                echo "user already exists"
        else
                useradd $user
                if [ $? -eq 0 ];then

                        echo "$user ok"
                else
                        echo "bad"
                fi
        fi

done < $1 #输入重定向,读取一行,否则退出

echo 

until应用,也非常适合处理文件!!!

  1. 普通的循环控制

    #!/usr/bin/bash
    
    ip=192.168.0.1
    until ping -c1 -W1 $ip&> /dev/null #ping 不通继续ping,使用while ping 成功继续ping
    do
    sleep 1
    done 
    echo "$ip is done"
    

shell多进程,命名管道和Fd

文件描述符FD

File Description 文件描述符 或者文件句柄

进程使用文件描述符来管理打开的文件

ll /proc/$$/fd #$$是当前进程的pid,在/proc/进程id号/fd

0 1 2 3 4 .....

0: standard input
1: standard output
2: standard error
4: 可用句柄

touch /file1
exec 6<> /file1 #打开文件,且控制文件描述符号为6

echo "hello" > /proc/$$/fd/6

cat /proc/$$/fd/6       #输出hello

cat /file1      #输出hello

exec 6<&- #关闭文件,且控制文件描述符号为6,如果打开后没有关闭,就删除了文件,该句柄依然在

再谈管道

匿名管道

管道也是个文件其实,用了就没了 |

命名管道

先进先出的管道,实现两个shell通讯

mkfifo /tmp/tmpfifo

cat <<-EOF
        +--------------------------------- -+
        0        1--stdout--stdin--->-0     1
        |process |                    |process|
        |        2                    |     2
        +-----------------------------------+
EOF

rpm -qa |grep bash


shell1.sh 多进程ping 无控制

#!/usr/bin/bash
# 读取user.txt文件,创建账号,其中line是读的一行,因为read是以换行符为结束
for i in {2...254} #or for i in `cat ip.txt`     #这里要执行cat ip.txt,所以要执行``或者${}

do
        {
        ip=192.168.0.$i
        ping -c1 -W.1 $ip&> /dev/null   #-c1 ping一次,-W.1等待0.1s
        if [ $? -eq 0 ]
        then
                echo "$ip is up"|tee -a ip.txt #usr tee type creat a file to record ping history
        else
                echo "$ip is down"
        fi
        }&      # 在(子shell)后台执行,相当于并发执行 多进程
done
wait    #等待前面所有后台进程结束
echo "finish"

shell2.sh 多进程创建用户

#!/usr/bin/bash
# 读取user.txt文件,创建账号,其中line是读的一行,因为read是以换行符为结束
for i in {1...1000} #or for i in `cat ip.txt`     #这里要执行cat ip.txt,所以要执行``或者${}

do
        {
        user=ttt$i
        useradd $user
        echo "111" |pass --stdin $user $>/dev/null
        if [ $? -eq 0 ]
        then
                echo "$user is up"|tee -a user.txt #usr tee type creat a file to record ping history
        else
                echo "$user is down"
        fi
        }&      # 在(子shell)后台执行,相当于并发执行 多进程
done
wait    #等待前面所有后台进程结束
echo "finish..."

shell3.sh 多进程ping 控制

当很多线程需要并发时,可以采用这个进行控制

#!/usr/bin/bash
# 读取user.txt文件,创建账号,其中line是读的一行,因为read是以换行符为结束
thread =5 #当很多线程需要并发时,可以采用这个进行控制
tmp_fifofile=/tmp/$$.fifo #当前pid命名
#创建管道
mkfifo $tmp_fifofile #创建管道文件
exec 8<> $tmp_fifofile #打开管道文件,并将句柄命名成8
rm $tmp_fifofile #删除文件,但是还保留句柄8


for i in `seq $thread` #for i in {1...$thread} #因为这里不识别变量,所有不能用这个判断

do
        echo >&8 #操作文件描述符8  echo相当于回车
done

for i in {1...254} #or for i in `cat ip.txt`     #这里要执行cat ip.txt,所以要执行``或者${}

do
        read -u 8 # read -u 读取文件描述符8,有数据 读到了才进行下去
        {
        user=ttt$i
        useradd $user
        echo "111" |pass --stdin $user $>/dev/null
        if [ $? -eq 0 ]
        then
                echo "$user is up"|tee -a user.txt #usr tee type creat a file to record ping history
        else
                echo "$user is down"
        fi
        echo >&8 #返回
        }&      # 在(子shell)后台执行,相当于并发执行 多进程
done
wait    #等待前面所有后台进程结束
exec 8>&- #释放文件描述符8,不是管道
echo "finish..."