例一:运算符的写法
a=1
let a++
let 'a+=2'
b=`expr $a + 3`         #注意=号两边不要有空格,还有+号两边要有空格
c=$((a+5))
d=$[a+7]


echo $a
echo $b
echo $c
echo $d


+
-
*
/
%
**


-------------------------------------------------------------------------


--常用的bash内部命令

echo     exit      continue      break

 例二:循环  (使用sh $0)

echo 'aaaaa'

sleep 3

sh $0  --这一句是代表再重新执行上面的代码  

exit 10 --这个定义退出整个脚本,但是在这个脚本里永远也到不了这一步

 

---------------------------------------------


for 循环语句 

  for  var    in  1 2 3 4 5
   do
    command
   done


  for (( var=1 ; var < 6 ; var++ ))
   do
    command
   done

  for (( var=5; var >0 ; var--))
   do
    command
   done


---------------------------------------------------------------------
 例三: for循环举例

for  i   in 1 2 3 4 5
do
        echo -ne "$i\n"--如果不使用-n参数,默认会一个数字打印一行,-e参数代表后面如果使用\n(换行),\t(制表符)等这种字符时会生效,所以这句和echo $i效果一样
done

 

for i  in `seq 100`  --产生1到100的序列
        do
        echo -n $i
done

for i in {50..100}
do
        echo -n $i
done
echo


for i in $(seq 100)  --也是产生1到100的序列,这是另一种写法
do
        echo -n $i
done

for  i  in  /etc/* --也可以把一个目录下面所有文件和目录循环赋值给变量i,常用于批量改名或改权限
        do
        echo $i
done

for i in /etc/*
do
        [ -f $i ] && echo $i --加一个判断,只要里面的文件
done


思考:
要把/etc/下所有的文件包括子目录下的文件也找出来,并echo出来

for i in `find /etc/ -type f`
do
        echo $i
done

find /etc/ -type f | while read i   --把前面find的结果通过管道read给i变量
do
        echo $i
done

 

 

批量加10个用户,以student1到student10命名,并统一加一个新组,组名为class,统一改密码为123(统一把密码改成就是自己的用户名,使用passwd命令和EOF结合?)


groupadd class

for i in `seq 10`
do
       useradd -G class "student$i"
       echo 123 | passwd --stdin "student$i" > /dev/null  2>&1
done


----------------
groupadd class

for i in `seq 10`
do

        useradd -G class "student$i"
passwd "student$i" <<EOF > /dev/null 2>&1
student$i
student$i
EOF  --注意这几行要顶格写
done

 

 

批量删除刚才建立的10个用户(包括把用户的家目录和邮件目录给删除干净)


for i in `seq 10`
do
        userdel -r "student$i"
done
groupdel class

 


计算1到100的奇数之和


total=0
for (( i=1 ;i <101 ;i+=2 ))
do
        total=$[$total+$i]
done
echo $total

 

total=0
for i in `seq 100`
do
        [ $[$i%2] -ne 0 ] && total=$[$total+$i]
done
echo $total

 

 

写一个脚本,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里(如果例举整个网段的254个IP花的时间比较长,可以只分类2.2.2.1到2.2.2.10这十个IP)


[ -e /tmp/upip ] && rm -rf /tmp/upip
[ -e /tmp/downip ] && rm -rf /tmp/downip

for i in `seq 10`
do
        ip="2.2.2.$i"
        a=`ping -c 1 $ip |grep  transmitted |cut -d" " -f4`
        [ $a -eq 0 ] && echo "$ip" >> /tmp/downip || echo "$ip" >> /tmp/upip
done


echo "能ping通的ip有:"
cat /tmp/upip

echo "#################"
echo "不能ping通的ip有:"
cat /tmp/downip

 

 

read输入一个目录,找出目录下为死链接的文件(同步也要判断子目录下的所有文件又如何写?)


read -p "输入一个目录:" dir

for i in $dir/*
do
        [ -h $i -a ! -e $i ] && echo "$i是死链接"
done


------------------------


read -p "输入一个目录:" dir

for i in  `find $dir -type l`
do
        [ ! -e $i ] && echo "$i是死链接"
done
  


用read输入一个目录,使用脚本判断目录里每个文件的权限(是否可读,是否可写,是否可执行)

#!/bin/bash


read -p "输入一个目录:" dir


[ -d $dir ] && echo "是一个目录,继续执行" || echo "不是一个目录,请重新运行脚本"


for i in `find $dir -type f`
do
        [ -r $i ] && r=yes || r=no
        [ -w $i ] && w=yes || w=no
        [ -x $i ] && x=yes || x=no

echo "当前用户对$i的权限为:"
echo $r
echo $w
echo $x

done

 


用read输入一个用户,再用read输入一个目录,使用脚本判断目录里每个文件的权限(read输入的用户对其是否可读,是否可写,是否可执行)
--提示:如何去用root用户去变成一个普通用户身份去执行脚本? man su 查看-c参数


--第一个脚本
[root@dns shell02]# cat example10.sh
#!/bin/bash


read -p "输入你要判断的用户名:" name

id $name > /dev/null 2>&1

if [ $? -eq 0 ];then
         echo "用户名存在,继续执行"
else
         echo "用户名不存在,请重新运行脚本,输入正确的用户名"
        exit 1
fi

su - $name -c "sh /tmp/example102.sh"

 

第二个脚本: --此脚本最后放到/tmp下,让所有用户可以执行
[root@dns shell02]# cat example102.sh
#!/bin/bash

user=`id | cut -d"(" -f2 |cut -d ")" -f1`   --查找自己的用户名,可以用whoami替代


read -p "输入一个目录:" dir


if [ -d $dir ];then
        echo "是一个目录,继续执行"
else
        echo "不是一个目录或目录不存在,请重新运行脚本"
        exit 1
fi

 

for i in `find $dir -type f`
do
        [ -r $i ] && r=yes || r=no
        [ -w $i ] && w=yes || w=no
        [ -x $i ] && x=yes || x=no

echo "$user对$i的权限为:"
echo "read=$r"
echo "write=$w"
echo "execute=$x"

done

 

 

=================================

 

until 循环 --直到满足条件就退出循环
 
 例十二:用until实现打印1到5
a=1
until [ $a -gt 5 ]    for ((a=1;a>5;a++))
do
        echo $a
        let a++
done

练习:
使用unitl去改写上面的批量加用户的脚本 

groupadd class

i=1
until [ $i -gt 10 ]
do

        useradd -G class "student$i"
passwd "student$i" <<EOF > /dev/null 2>&1
student$i
student$i
EOF  
let i++
done


=====================================================

while  用于不定次数的循环,或死循环

while  [条件]
do
 command
done


死循环两种:

while true
do
 command
done

while :
do
 command
done


写一个30秒就时间同步2.2.2.35一次的脚本


while true
do
        rdate -s 2.2.2.35
        sleep 30
done


--不定次数循环,当满足一定条件,就退出循环
while true
do
        rdate -s 2.2.2.35  > /dev/null 2>&1
        [ $? -ne 0 ] && echo "rdate failed" | mail root && exit 100
        sleep 30
done

 

写一个小闹钟的程序  (每秒都显示时间,当到了时间,就循环打印5个*,间隔一秒)


while true
do
        now=`date +%H:%M:%S`
        echo $now
        sleep 1
        clear
        if [ "$1" == "$now" ];then
                for (( i=0;i<10;i++))
                do
                        echo -n "*"
                        sleep 1
                done
                break  --在这里是表示打完*后,跳出循环,继续执行循环体后面的代码;如果换成exit则表示直接退出脚本
        fi
done

echo
echo 'it is time'


#!/bin/bash


read -p "输入你定时的时间(格式为时:分:秒):" ntime

while true
do
        now=`date +%H:%M:%S`
        echo $now
        sleep 1
        clear
        if [ "$ntime" == "$now" ];then
                for (( i=0;i<10;i++))
                do
                        echo -n "*"
                        sleep 1
                done
                break
        fi
done

echo
echo "时间到了"

 

break  continue  exit
--continue表示循环体内下面的代码不执行,重新开始循环
--break表示跳出循环体,执行循环体外的下面的代码
--exit表示直接跳出程序

 

写一个简单的猜数字的脚本


#!/bin/bash

num=74

while true
do
        read -p "guess your number:" guess

        [ $guess -gt $num ] && echo "大了" && continue 
        [ $guess -lt $num ] && echo "小了" && continue
        [ $guess -eq $num ] && echo "对了" && break
done

echo "砸蛋"

 

 

找出/etc/的所有以conf结尾的文件,拷到/tmp/conf目录下,然后全部把conf结尾换成以html结尾

[ -d /tmp/conf ] &&  rm /tmp/conf -rf && mkdir /tmp/conf

find /etc/ -name "*.conf" -exec cp {} /tmp/conf \;
cd /tmp/conf
rename .conf .html *

 

------------

#!/bin/bash

if [ -d /tmp/conf ];then
         rm -rf /tmp/conf
         mkdir /tmp/conf
else
        mkdir /tmp/conf
fi


find /etc/ -name "*.conf" -exec cp {} /tmp/conf \;

cd /tmp/conf

for i in ./*
do
        head=`echo $i |awk -F".conf" '{print $1}'`
        mv $i $head.html
done

 

找出/usr/share/doc目录下所有文件名为index.html的文件,把他们拷到/tmp/index目录下,文件名按找到的先后更改,第一个找到的为index.html.1,第二个找到的为index.html.2。。。。类推


[ -e /tmp/index -a  -d /tmp/index ] && rm -rf /tmp/index && mkdir /tmp/index

i=1
find /usr/share/doc/ -name index.html | while read a
do
        cp $a /tmp/index/index.html.$i
        let i++
done

 

==============================================================

===========================

循环嵌套

 
打印出
1  
12
123
1234
12345

*
**
***
****
*****
******

*
**
* *
*  *
*   *
******


第一种写法:
a=1
while [ $a -lt 6 ]
do
        for (( b=1;b<=$a;b++ ))
        do
                echo -n $b
        done
        let a++
        echo
done
第二种写法:
a=1
while [ $a -lt 6 ]
do
        b=1
        while [ $b -le $a ]
        do
                echo -n $b
                let b++
        done
        let a++
        echo
done


===================================================================

随机数:
bash默认有一个$RANDOM的变量  使用set |grep RANDOM 查看上一次产生的随机数


echo $RANDOM

#产生0到1的随机数
ran1=`expr $RANDOM % 2`
echo $ran1

#产生100到200的随机数
ran2=`expr $RANDOM % 101 + 100`
echo $ran2

#产生50到100的随机数
ran3=$((RANDOM % 101))
while [ "$ran3" -lt 50 ]
        do
        ran3=$((RANDOM % 101))
done
echo $ran3

 

产生100内的随机数
echo $[$RANDOM%101]

产生0-1之间的随机数
echo $[$RANDOM%2]

产生1-2之内的随机数
echo $[$RANDOM%2+1]

产生50-100之内的随机数
echo $[$RANDOM%51+50]

产生三位数的随机数
echo $[$RANDOM%900+100]


=========================================================
题目:


随机产生一个三位数,按位数一个一个的猜,每位只有五次猜的机会,直到猜成功

echo $[$RANDOM%900+100]


cut

#!/bin/bash

num=`echo $RANDOM`

while true
do
        one=`echo $num | cut -c 1`
for i in 1 2 3 4 5
do
        read -p "请猜第一个数第$i次:" guess
                if [ $guess -eq $one ];then
                        echo "你猜对了第一个数字,请猜第二个数字"
                        break
                fi
                [ $i -eq 5 ] && echo "五次机会用完" && exit 1
done    

        two=`echo $num | cut -c 2`
for i in 1 2 3 4 5
do
        read -p "请猜第二个数第$i次:" guess
                if [ $guess -eq $two ];then
                        echo "你猜对了第二个数字,请猜第三个数字"
                        break
                fi
                [ $i -eq 5 ] && echo "五次机会用完" && exit 1
done    
        three=`echo $num | cut -c 3`
for i in 1 2 3 4 5
do
        read -p "请猜第三个数猜第$i次:" guess
                if [ $guess -eq $three ];then
                        echo "你猜对了第三个数字"
                        break
                fi
                [ $i -eq 5 ] && echo "五次机会用完" && exit 1
done    
                break
done
echo "恭喜猜对了,正确数字为$num"

 

 

将/etc/passwd里的用户名分类,分为管理员用户,系统用户,普通用户


#!/bin/bash

for i in `cat /etc/passwd |cut -d: -f1,3`
do
        uid=`echo "$i" |cut -d: -f2`
        name=`echo "$i" |cut -d: -f1`
        [ $uid -eq 0 ] && echo "$name" >> /tmp/adminuser
        [ $uid -lt 500 -a $uid -gt 0 ] && echo "$name" >> /tmp/systemuser
        [ $uid -eq 65534 ] && echo "$name" >> /tmp/systemuser
        [ $uid -gt 500 -a $uid -ne 65534 ] &&  echo "$name" >> /tmp/nomaluser
done

 

写一个脚本把一个目录内的所有空文件都删除,最后输出删除的文件的个数

read -p "输入一个你要删除空文件的目录:" dir

a=0
for i in `find $dir -type f`
do
 [ ! -s $i ] && rm -rf $i && let a++
done

echo "删除的个数为:" "$a" 


-----------------------------------

--下面这种写法有问题,循环内部let a++确实加了值,但循环之后的a值还是为0
a=0

find $dir -size 0c | while read i
do
        rm -rf $i && let a++
done

echo $a   --???????

 


写一个倒计时脚本,要求显示离2012年1月1日的凌晨0点,还有多少时间


#!/bin/bash

while true
do
        year=$[2011-`date +%Y`]
        month=$[12-`date +%m`]
        day=$[31-`date +%d`]
        hour=$[23-`date +%H`]
        minute=$[59-`date +%M`]
        second=$[60-`date +%S`]
echo "离2012年还有$year年:$month月:$day天:$hour时:$minute分:$second秒"
        sleep 1
done

--上面的问题大概有几个:
1.倒计时不用月,因为每月的天数不一样。只用天的话,用365去减也不准确,因为闰年是366天
2,当分钟为0几分时,如08分  那么59-08,它不能减


--正确写法如下:
#!/bin/bash


goal=`date +%s -d 20120101`

while true
do
        now=`date +%s`
        day=$[($goal-$now)/86400]
        hour=$[($goal-$now-$day*86400)/3600]
        minute=$[($goal-$now-$day*86400-$hour*3600)/60]
        second=$[$goal-$now-$day*86400-$hour*3600-$minute*60]
        echo "离2012年还有$day天:$hour时:$minute分:$second秒"
        sleep 1
done