shell 循环语句

一、命令补充

1. echo 命令

echo -n   表示不换行输出
echo -e   表示输出转义符

常用的转义符有:

选项 作用
\r 光标移至行首,并且不换行
\s 当前shell的名称,如bash
\t 插入Tab键,制表符
\n 输出换行
\f 换行,但光标仍停留在原处
\ 表示插入"\"本身转义
\b 表示退格 不显示前一个字符
\c 抑制更多的输出或不换行

关于 \b 用法

[root@localhost ~]#echo -e "12345\b678"
##退格删除前面的字符
1234678
[root@localhost ~]#echo -e "12345\b\b678"
123678
[root@localhost ~]#echo -e "12345\b\b\b678"
12678
[root@localhost ~]#echo -e "12345\b\b\b\b678"
16785
###注意退格键和末尾的字符相关,超过末尾的字符数量 会出bug

关于换行

[root@localhost ~]#echo  "123456"
123456
#正常换行输出

[root@localhost ~]#echo -n "123456"
123456[root@localhost ~]#
#不换行输出

[root@localhost ~]#echo -e "123456\c"
123456[root@localhost ~]#
[root@localhost ~]#echo -e "123456\c789"
123456[root@localhost ~]#

###\c 注意 使用在数字中间会把后面内容删除


使用 \n 可以实现输出换行(回车)的操作。


比如实现自动硬盘分区

#!/bin/bash
read  -p   "请输入你要分区的设备(/dev/sd*):"   disk
read  -p   "请输入你要分区的大小(+数字G):"   num

echo  -e  "n\n\n\n\n${num}\nw\n " | fdisk ${disk}

2. data 命令

  • date查看当前系统时间
  • -d  你描述的日期,显示指定字符串所描述的时间,而非当前时间
  • %F    完整日期格式,等价于 %Y-%m-%d
  • %T 时间(24小时制)(hh:mm:ss)
[root@localhost data]#date           #查看当前系统时间
2024年 01月 25日 星期四 22:33:46 CST

[root@localhost data]#date  +%F      #完整格式显示日期
2024-01-25

[root@localhost data]#date  +%T      #完整格式显示时间
22:40:39

[root@localhost data]#date  +%F-%T   #时间与日期使用 - 号分隔
2024-01-25-22:42:37
[root@localhost data]#date  '+%F   '%T    #时间与日期使用 空格 号分隔
2024-01-25   22:42:48


[root@localhost data]#date -d "-3 day"    #前三天
2024年 01月 22日 星期一 22:45:40 CST

[root@localhost data]#date -d "+3 day"    #后三天
2024年 01月 28日 星期日 22:45:46 CST

[root@localhost data]#date -d '-3 day'  '+%F   '%T
2024-01-22   22:46:20


日历:
[root@localhost data]#cal 2024
#查看日历

[root@localhost data]#cal  9 2024    #查看哪一年哪一月的日历。
      九月 2024     
日 一 二 三 四 五 六
 1  2  3  4  5  6  7
 8  9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30



关于 计划任务 crontab 里 不能有 % 号,想要使用 要加 \ 转义符

30 2 * * * /bin/cp -a /etc/ /data/etc`date +\%F_\%T`

!!!!!!!!!不加转义符号无法识别!!!!!!!!!!!
30 2 * * * /bin/cp -a /etc/ /data/etc`date +‘%F_%T’`   #无法执行。

3. seq

[root@localhost data]#seq 3
1
2
3


[root@localhost data]#seq 1 2 10
#从1 开始 步长为2  到10 为止
1
3
5
7
9

[root@localhost data]#seq 0 2 10
#从 0 开始 步长为 2  到10 为止 都为偶数。
0
2
4
6
8
10

[root@localhost data]#seq 3 -1 1
#从 3 开始 依次 减 1 ,到 1 为止。
3
2
1

[root@localhost data]#seq 3 -1 -1
3
2
1
0
-1

二、for 循环

循环含义

将某代码段重复运行多次,通常有进入循环的条件和退出循环的条件

重复运行次数

  • 循环次数事先已知       for
  • 循环次数事先未知      while    until

常见的循环的命令:for, while, until

列表循环

语法:

for 变量名 in   {list}
do
    command(需要循环的事件)
done



for i in {1..10}
do
  echo "i=$i"
done


1.for循环有次数
2.for循环开始时,会对变量i进行赋值
3.for循环在赋值后,会执行do 和done之间的代码
4.for循环在第一次循环后执行到done,再次赋值第二个
5.for循环在赋值后,会执行do 和done之间的代码
6.for循环在第一次循环后执行到done,再次赋值第三个
7.for循环在赋值后,会执行do 和done之间的代码

花括号的用法

花括号{}和seq在for循环的应用:
for i in {1..50..2} 1-50的奇数
do
    echo "$i"
done

for i in {2..50..2} 2-50的偶数
for i in {10..1}  1-10倒序排列


$() 和 `` 都是调用命令的执行结果。

for i in $(seq 10)  1-10正序排列
for i in $(seq 10 -1 1) 1-10倒序排列
for i in $(seq 1 2 10) 1-10的奇数,中间为步长

#要想有结果要在后面输入完整的格式。
不带列表循环

语法:

for 变量名 
do
    command
done

例子:

1. 打印 hello
[root@server ~]# vim for2.sh 

#!/bin/bash
for i
do
        echo hello
done

[root@server ~]#bash for2.sh   
#没有给脚本传参所以执行了没有结果

[root@server ~]#bash for2.sh a   
#把a赋值给变量i,i有值了它就开始执行do..done了
hello
类似于C语言风格的for循环

语法:

for (( 表达式1; 表达式2; 表达式3 )); do 命令; done


for ((expr1;expr2;expr3))
do
       command
done


expr1:定义变量并赋初值
expr2:决定是否循环
expr3:决定循环变量如何改变,决定循环什么时候退出

比如:

sum=0
for ((i=0;i<=100;i++))
do
  sum=$[sum+i]
done
echo "$sum"

计算 1 到 100 累加的值 5050


i=0 是给 i 变量赋值为 0
i<=100   是定义 变量的范围 在范围内继续循环,不在结束循环。
i++   是 变量 i 每运行一次都会加1。


let sum+=i    等于   let sum=sum+i  
#需要使用 let  命令


++	自身变量+1
--  自身变量-1
+=5	自身变量+5
-=5	自身变量-5
*=5	自身变量*5
/=5	自身变量/5
%=5	自身变量%5

例子:

使用脚本 输出 十次 hello world 。

#!/bin/bash
for i in {1..10}
do
  echo "hello world"
done

不编辑脚本 使用命令 输出 十次 hello world 。

[root@localhost data]#for i in {1..10};do echo "hello world";done
或
[root@localhost data]#for i in `seq 10`;do echo "hello world";done
使用三种方法过滤出当前目录下 以 sh 结尾的文件 且 只显示文件名。

[root@localhost data]#ls|grep sh$

[root@localhost data]#find  -name '*sh'|cut -d "/" -f2

[root@localhost data]#for i in *sh;do echo $i;done
#当前目录下以sh 结尾的文件名 会赋值给 变量 i ,然后输出变量,然后循环 直至 全部输出 停止循环。
 一 到 一百 奇数和 与 偶数和。
[root@localhost data]#vim he.sh


#!/bin/bash
sum=0
for i in {1..100..2}
do
  sum=$[sum+i]
done
echo "1到100的奇数和为:$sum"

sum=0
for i in {0..100..2}
do
  sum=$[sum+i]
done
echo "1到100的偶数和为:$sum"

[root@localhost data]#bash he.sh 
1到100的奇数和为:2500
1到100的偶数和为:2550


另一种格式:
#!/bin/bash
sum=0
for ((i=0;i<=100;i+=2))
do
  sum=$[sum+i]
done
echo "$sum"

sum=0
for ((i=1;i<=100;i+=2))
do
  sum=$[sum+i]
done
echo "$sum"
九九乘法表:
正 九九乘法表

#!/bin/bash
for j in {1..9}
do
  for i in `seq $j`
  do
    echo -e "${i}x${j}=$[i*j]\t\c"
#\t 可以对齐
#\c 不换行(要放在最后)
  done
echo
done


倒 九九乘法表

#!/bin/bash
for j in {9..-1..1}
do
  for i in `seq $j`
  do
    echo -e "${i}x${j}=$[i*j]\t\c"
  done
echo
done
批量添加用户
#!/bin/bash
read -p "请输入你要添加的用户名称:" usr

for uname in $usr
do
   useradd $uname
   echo "123123" |passwd --stdin  $uname &>/dev/null
done



或


#!/bin/bash
ulist=$(cat /opt/user.txt) #用户名称文件
for uname in $ulist
do
   useradd $uname
   echo "123123" |passwd --stdin  $uname &>/dev/null
done

[root@localhost ~]#cat /opt/user.txt
lisi
wangwu
zhangsan
ping 一个网段内所有的ip地址
#!/bin/bash
ip=192.168.80.
for i in {1..254}
do
{
  ping -c2 -W2 ${ip}${i} &> /dev/null
  if [ $? -eq 0 ];then
    echo "$i is up" >> /mnt/up.txt
#正确结果追加到/mnt/up.txt 文件里
    else
    echo "$i is down" >> /mnt/down.txt
#错误结果追加到/mnt/down.txt 文件里
  fi
} &
done
批量改后缀名:
#!/bin/bash
read -p "你想要在mnt目录下改什么后缀的文件(输入后缀):" w
b=`find /mnt/* -name "*.${w}" | wc -l`
if [ $b -gt 0 ];then
  read -p "你想要改后缀为:" h
  file=`ls /mnt/*.${w}|cut -d "/" -f3`
    for i in $file
    do
      name=`echo $i | cut -d "." -f1`
      mv /mnt/$i /mnt/${name}.${h}
    done
else
  echo -e "\E[1;35m没有这个后缀的文件\E[0m"
  echo
  bash $0
fi



纯属乱加的,^-^


批量改后缀名:
DIR=/data/test
cd $DIR || {  echo 无法进入 $DIR;exit 1; }
for FILE in * 
do
 PRE=`echo $FILE|grep -Eo ".*\."`
    mv $FILE ${PRE}bak
done  



#!/bin/bash
cd /data
for file in *
do
name=`echo $file |cut -d "." -f1`
mv $file   ${name}.bak
done
关于随机取值

$RANDOM   取值范围: 0-32767

[root@test1 ~]# echo $[$RANDOM%50]
37
#随机输出 0-49 以内的随机数。

[root@test1 ~]# echo $[$RANDOM%50+1]
1
#随机输出 1-50 以内的随机数。

三、 while

相对于for,需要知道循环次数

我们只知道停止条件,不知道次数,就需要使用 while

直到达到条件

  while循环
  1、语法结构
  2、死循环

while循环一般用于有条件判断的循环,若判断条件为真,则进入循环,当条件为假就跳出循环

格式:

while  条件判断
do
  命令
done


当命令判断为假时停止

死循环:

while死循环
while [ 1 -eq 1 ]  //写一个永远为真的表达式,1等于1这个条件永远为真,所以这个脚本会一直循环下去
do
    command
done
#因为1 永远等于 1 ,所以会一直循环。




while true
do
    command
done



while :
do
    command
done


: 是一个空的命令。没有效果; 此命令不做任何操作。 表示总是成功(总为真)
批量建立用户
#!/bin/bash
i=1
while [ "${i}" -le 33 ]
#循环33次 ,变量小于等于33
do
useradd stu${i}
#建立stu1 至 stu33 的用户
echo "123456" |passwd --stdin stu${i} &>/dev/null
if [ $? -eq 0 ]
#使用 $? 判断上一次命令执行结果是否为0(真)
then
echo "用户 stu${i} 被建立"
#等于 0 执行上面语句,不等于执行下面语句
else
echo "用户 stu${i} 建立失败"
fi
let i++
#每循环一次都要给变量加1。
done
猜价格游戏
while 格式

#!/bin/bash
p=`echo $[RANDOM%2000+1]`
t=0

while true
do
read -p "请输入商品的价格1-1000:" num
let t++
if [ $num -eq $p ]
then
echo "恭喜你猜中了,实际价格是$p"
echo "您一共猜了${t}次"
exit 0
#退出循环,不加会一直循环。
elif [ $num -gt $p ]
then
echo "您猜的价格高了" 
else
echo "您猜的价格低了"
fi
done

四、双重循环以及跳出循环

  • break跳出单个循环 break n 数字数字是几代表跳出n层循环

  • continue终止某次循环中的命令,但是不会完全终止命令

  • exit 直接退出脚本

关于 continue 

[root@localhost ~]#cat continue.sh 
#结束某次循环
#!/bin/bash
for i in {1..10}
do
if [ $i -eq 5 ]
then continue 
fi
echo i=$i
done

#then后面加上continue 的意思是当变量等于 5 时终止当前循环,但第 6 次循环还会继续执行。

关于 break

[root@localhost ~]#cat break.sh 
#结束一层循环
#!/bin/bash
for j in {1..9}   #行数
do
        for i in {1..9}  #列数
        do
        if  [ $i -eq 5 ]
        then
        break
        fi
        echo -n "i=$i   "
        done
echo
done

#结果 等于 5 时直接结束 本层 循环。 for j in {1..9} 还会继续执行。

[root@localhost dst]#bash break.sh 
i=1   i=2   i=3   i=4   
i=1   i=2   i=3   i=4   
i=1   i=2   i=3   i=4   
i=1   i=2   i=3   i=4   
i=1   i=2   i=3   i=4   
i=1   i=2   i=3   i=4   
i=1   i=2   i=3   i=4   
i=1   i=2   i=3   i=4   
i=1   i=2   i=3   i=4

#可以看到 到第四列的时候就没有了 ,这是因为 负责列数的循环已经停止执行了,但行数的
循环还在执行,所以就会出现 九行 四列的情况。

关于 exit

[root@localhost ~]#cat break.sh 
#结束一层循环
#!/bin/bash
for j in {1..9}     #行数
do
        for i in {1..9}    #列数
        do
        if  [ $i -eq 5 ]
        then
        exit
        fi
        echo -n "i=$i   "
        done
echo
done

#这个将更加暴力,执行第一次行数循环 后 列数的循环执行到第五次将直接退出脚本,不再执行任何的循环。

[root@localhost dst]#bash break.sh
i=1   i=2   i=3   i=4   [root@localhost dst]#

五、until 循环

        until 循环与 while 循环类似,while 循环能实现的脚本 until 同样也可以实现,但区别是while 循环在条件为真是继续执行循环,而 until 则是在条件为假时执行循环

until 循环语句的语法结构如下所示。

until 条件测试操作
do
命令序列
done

实例1:求和

#!/bin/bash
sum=0
i=0
until [ $i -gt 100 ]
#变量 i 为假 (不大于 100),将执行循环,当变量大于100退出循环。
do
let sum=$i+$sum
let i++
done
echo sum=$sum

实例2:判断用户是否在线,在线就发消息。

#!/bin/bash
username=$1
if [ $# -lt 1 ]
then
echo "请在脚本后输入 用户名和发送信息" 
exit 1
fi

if  grep "^$username" /etc/passwd &>/dev/null
then :
else
 echo "用户不存在"
 exit 1
fi


until who |grep $username &>/dev/null
do
echo "用户不在线"
sleep 5
done

mes=$2
echo $mes |write $username

select 菜单选择

[root@localhost data]#help select
select: select NAME [in 词语 ... ;] do 命令; done
    从列表中选取词并且执行命令。
    
    WORDS 变量被展开,生成一个词的列表。展开的词集合被打印
    在标准错误输出设备上,每个以一个数字做前缀。如果没有 `in WORDS'
    则假定使用`in "$@"'。PS3提示符会被显示并且从标准输入读入一行
    如果该行由被显示的词对应的数字组成,则 NAME 变量被设定为相应
    的词。如果行为空,则 WORDS 变量和提示符被重新显示。如果读取了
    文件结束符,则命令完成。读入任何其他的值会导致 NAME 变量被设定
    为空。读入的行被存放在变量 REPLY 中。COMMANDS 命令在每次选择
    之后执行直到执行一个 break 命令。
    
    退出状态:
    返回最后一个执行的命令的状态。


一定要使用$REPLY
[root@localhost ~]#select menu in 配置网卡 配置yum源;do echo $menu;done
1) 配置网卡
2) 配置yum源
#? 1
配置网卡
#? 2
配置yum源
#? 
[root@localhost ~]#PS3="请选择功能(1-2):";select menu in 配置网卡 配置yum源;do echo $menu;done
1) 配置网卡
2) 配置yum源
请选择功能(1-2):1
配置网卡
请选择功能(1-2):2
配置yum源
请选择功能(1-2):


PS1 提示符
PS2 多行重定向
PS3 菜单选择

例子:

#!/bin/bash
sum=0
PS3="请输入(1-6):"
MENU="
宫保鸡丁
酸菜鱼
鱼香肉丝
佛跳墙
水煮肉片
点菜结束
"

select menu in $MENU
do
case $REPLY in
1)
echo $menu 价格是20
let sum+=20
;;
2)
echo $menu 价格是60
let sum+=60
;;


3)
echo $menu 价格是25
let sum+=25
;;

4)
echo $menu 价格是150
let sum+=150
;;

5)
echo $menu 价格是60
let sum+=60
;;

6)
echo "点菜结束"
break
;;

*)
echo "点菜错误,请重新选择"
;;

esac
done

echo "总价是$sum"

EOF 菜单

#!/bin/bash
cat  <

你可能感兴趣的:(linux,运维,服务器)