1:while 循环和 until 循环
while 循环是用来重复执行一组命令或语句常用与守护进程或者持续运行的程序
可以是次数固定的,也可以是不固定的
语法
while 条件测试
  do
    循环体内部逻辑
  done
  
  
until 和 while 相反,到达某个条件不成立时,进入循环体执行指令,表达式成立时,跳出循环
语法
until 条件测试
  do
    循环体
 done
         
while 代码案例
[root@hadoop ~]# cat  while_create_user.sh
#! /bin/bash
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 is already exists"
    else
      useradd $user
      echo "$pass" | passwd --stdin "$user" &>/dev/null
      if [ $? -eq 0 ];then
         echo "$user create success...."
      fi
    fi
done < user2.txt


chmod +x while_create_user.sh

在user2.txt中添加
liyifei  000
yangmi   111
cangjinkong 222
jizemingbu  333

user add cangjingkong
user add jizemingbu

./while_create_user.sh  执行结果如下
[root@hadoop ~]# ./while_create_user.sh
useradd:警告:此主目录已经存在。
不从 skel 目录里向其中复制任何文件。
正在创建信箱文件: 文件已存在
liyifei create success....
useradd:警告:此主目录已经存在。
不从 skel 目录里向其中复制任何文件。
正在创建信箱文件: 文件已存在
yangmi create success....
cangjinkong is already exists
jizemingbu is already exists

另一种方式
#!/bin/bash
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 is already exists"
    else
        useradd "$user"
        # 使用chpasswd来设置密码(更可靠的方法)
        echo "${user}:${pass}" | chpasswd
        if [ $? -eq 0 ]; then
            echo "$user create success...."
        else
            echo "Failed to set password for $user"
        fi
    fi
done < user2.txt


将判断语句缩写一下
#!/bin/bash
while read line
do
    if [ ${#line} -eq 0 ]; then
        echo "---------------------------"
        continue
    fi
    
    user=$(echo "$line" | awk '{print $1}')
    pass=$(echo "$line" | awk '{print $2}')
    
    if id "$user" &>/dev/null; then
        echo "$user already exists"
    else
        if useradd "$user"; then
            if echo "$pass" | passwd --stdin "$user" &>/dev/null; then
                echo "$user create success...."
            else
                echo "Failed to set password for $user"
                # 可以考虑删除创建的用户
                userdel "$user"
            fi
        else
            echo "Failed to create user $user"
        fi
    fi
done < user2.txt

案例2 : while 循环探测远程主机是否在线
方案1:监控 IP 下线(当前逻辑)

#!/bin/bash
ip=192.168.88.103
while ping -c1 -W1 $ip &>/dev/null
do
    sleep 1
done
echo "$ip is down"


方案2:等待 IP 上线
#!/bin/bash
ip=192.168.88.103
while ! ping -c1 -W1 $ip &>/dev/null
do
    sleep 1
done
echo "$ip is up"
方案3:增强版本(带状态显示)

#!/bin/bash
ip=192.168.88.103
echo "Monitoring $ip..."

while true
do
    if ping -c1 -W1 $ip &>/dev/null; then
        echo "$(date): $ip is up"
    else
        echo "$(date): $ip is down"
    fi
    sleep 1
done

方案4:超时控制版本

#!/bin/bash
ip=192.168.88.103
timeout=60
count=0

echo "Waiting for $ip to come online (timeout: ${timeout}s)..."

while [ $count -lt $timeout ]
do
    if ping -c1 -W1 $ip &>/dev/null; then
        echo "$ip is now online!"
        exit 0  #正常退出
    fi
    sleep 1  #默认是秒
    count=$((count + 1))
done

echo "Timeout: $ip did not come online within ${timeout} seconds"
exit 1   #异常退出

until 循环的案例
[root@hadoop ~]# vim until_ping.sh
#! /bin/bash
ip=192.168.88.103
until ping -c1 -W1 $ip &>/dev/null
  do
    sleep 1
  done
echo "$ip is up"
[root@hadoop ~]# cat until_ping.sh
[root@hadoop ~]# chmod +x until_ping.sh
[root@hadoop ~]# ./until_ping.sh
192.168.88.103 is up

do 和 done 之间只有一个语句的时候可以省略{}
  do
    sleep 1
  done
当存在多个语句是需要大括号,{}&  + wait组合 表示后台处理,并且是并发的处理
 do
 {}
 done  
 
 

for 循环实现并发控制案例 
1:非并发的情况
[root@hadoop ~]# cat noparell.sh
#! /bin/bash
start=`date +%s`
for ((i=1;i<=1000;i++))
   do
      sleep 1
      echo "$i success"
   done
end=`date +%s`
echo "cost time: `$end-$start`"
执行结果,每秒执行一次,需要同步等待到循环全部执行完成再打印消费的时间

并发的写法
[root@hadoop ~]# cat parell.sh
#!/bin/bash
start=`date +%s`
for ((i=1;i<=1000;i++))
do
    {
        sleep 1
        echo "$i success"
    }&
done
wait
end=`date +%s`
cost=$((end - start))
echo "cost time is: $cost"

执行结果
991 success
993 success
1000 success
995 success
994 success
988 success
984 success
990 success
cost time is: 2

用{} 括起来 后面加一个& 表示每次都将命令放到后台运行
循环1000次就会有1000个& 把任务放到后台,操作系统会并发1000个线程来执行这些任务

wait 命令等待上一个命令执行完了再执行,一条命令一旦交给后台,shell就会往下执行
只要遇到 & 就会将任务交给后台,具体什么时候执行,有操作系统的cpu自行分配时间片
执行顺序是无序的

==============================================================
linux 管道实现shell 的并发控制  todo  (需要补充管道的知识)

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


linux 中 (()) []  {} 的用途

在 Linux Shell 中,(())、[]、{} 是三种不同的语法结构,各有特定的用途:

1. (()) - 算术运算
用途:整数算术计算

# 基本算术运算
a=5
b=3
echo $((a + b))        # 输出: 8
echo $((a * b))        # 输出: 15
echo $((a % b))        # 输出: 2

# 自增自减
((a++))                # a=6
((b--))                # b=2

# 复合运算
((a += 5))             # a=11
((b *= 3))             # b=6
在条件判断中

if ((a > b)); then
    echo "a is greater than b"
fi

for ((i=0; i<5; i++)); do
    echo "i = $i"
done
2. [] 或 test 命令
用途:条件测试

# 文件测试
if [ -f "/etc/passwd" ]; then
    echo "File exists"
fi

if [ -d "/tmp" ]; then
    echo "Directory exists"
fi

# 字符串比较
name="John"
if [ "$name" = "John" ]; then
    echo "Hello John"
fi

if [ -n "$name" ]; then
    echo "Name is not empty"
fi

# 数值比较
a=10
b=20
if [ $a -lt $b ]; then
    echo "a is less than b"
fi
常用测试运算符:
bash
# 文件测试
[ -f file ]    # 文件存在且是普通文件
[ -d dir ]     # 目录存在
[ -r file ]    # 文件可读
[ -w file ]    # 文件可写
[ -x file ]    # 文件可执行

# 字符串测试
[ -z str ]     # 字符串为空
[ -n str ]     # 字符串非空
[ str1 = str2 ] # 字符串相等
[ str1 != str2 ] # 字符串不等

# 数值比较
[ a -eq b ]    # 等于
[ a -ne b ]    # 不等于
[ a -lt b ]    # 小于
[ a -le b ]    # 小于等于
[ a -gt b ]    # 大于
[ a -ge b ]    # 大于等于
3. {} - 代码块和扩展
用途1:代码块(命令分组)

# 在当前shell执行(影响当前环境)
{
    cd /tmp
    ls -l
    pwd
}

# 在子shell执行(不影响当前环境)
(
    cd /tmp
    ls -l
    pwd
)
echo "Back to: $(pwd)"  # 仍然在原始目录
用途2:大括号扩展

# 生成序列
echo {1..5}            # 输出: 1 2 3 4 5
echo {a..e}            # 输出: a b c d e
echo {01..10}          # 输出: 01 02 03 ... 10

# 组合扩展
echo {A,B,C}{1,2}      # 输出: A1 A2 B1 B2 C1 C2

# 文件操作
touch file{1..3}.txt   # 创建 file1.txt, file2.txt, file3.txt
mkdir {bin,lib,src}    # 创建三个目录
用途3:变量操作

name="filename"
echo ${name}           # 基本变量引用
echo ${name%.*}        # 去除后缀: filename
echo ${name#*.}        # 去除前缀(如果有后缀)

# 默认值设置
echo ${VAR:-default}   # 如果VAR未设置,使用default
echo ${VAR:=default}   # 如果VAR未设置,设置VAR为default
综合比较示例

#!/bin/bash

# (()) 用于算术
a=10
b=5
((result = a + b))
echo "Arithmetic: $result"

# [] 用于条件测试
if [ $a -gt $b ]; then
    echo "Condition: a > b"
fi

# {} 用于代码块和扩展
{
    echo "Block: Starting task"
    sleep 1
    echo "Block: Task completed"
}

# 大括号扩展
echo "Expansion: "{1..3}
记忆技巧
(()):算术运算(Arithmetic)

[]:条件测试(Condition/Test)

{}:代码块和扩展(Block/Expansion)

现代替代语法
[[]]:增强版条件测试(推荐)

(()):算术运算

$():命令替换(替代反引号)``


# 推荐使用 [[]] 代替 []
if [[ $name == "John" && $age -gt 18 ]]; then
    echo "Welcome John"
fi
这三种语法结构是 Shell 编程的基础,熟练掌握它们对于编写高效的脚本非常重要

 
 
 


         

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐