Shell while循环语句中的陷阱

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Shell while循环语句中的陷阱相关的知识,希望对你有一定的参考价值。

参考技术A 我们经常使用while来循环读取文件的每一行,并用文件中的数据对变量赋值,典型写法如下

结果显示两次value打印都是0,循环中的赋值没有起作用。问题出在这种while写法上,cat file |  while read 的意思是: 使用 cat 命令查看文件,通过管道将结果传送给包含 read 命令的 while 命令,会每次读取文件中的一行文本,传给read后的参数,参数可以为多个,默认以空格分隔,当文件中没有可读取的文本时,read 命令将以非零状态退出。 这就意味着while循环中的程序实际上是在一个子进程中执行的,当前进程通过管道将文件内容传递到子进程。循环体中的value并非是外部定义的value,在循环体中对value赋值自然也不能改变外部value的值。

解决方法是换一种读文件的方法,将循环体放到当前进程中执行。

cat file | while read 是一种很不友好的写法,虽然最常用,但是效果最差。 推荐使用以上<data.txt的读文件方法。

用上述cat | while写法读文件时还可能碰见另一个问题:读不到文件的最后一行。如data.txt文件的内容如下

用上述cat | while写法则可能只会读到222,最后一行333被忽视了。上文已经说到while如果判断没有可读取的文本时就会退出,while判断是否到达文件末尾是识别文件结束符EOF。文件最后一行之后如果没有换行符\n,则read读取最后一行时遇到EOF,循环即终止。此时虽在内存有最后一行,但程序已经没有机会再处理此行内容。

知道原因了就可以解决这个问题,权宜之计是在最后一行的后面再换个行。治标的方法是用dos2unix将文件格式转换为Unix,因为缺少换行符一般是由于Windows文件传到Linux没有转换格式。

Linux命令行真的是宝藏,功能丰富,用法多样。如果Linux的生态圈能够更发达一点,说不定以后Linux

会是家庭电脑的主流操作系统。

Shell脚本------循环语句(for,while,until循环语句)

一.echo语句

echo  -n       表示不换行输出
echo  -e       输出转义字符,将转义后的内容输出到屏幕上

✪常用的转义字符
\\b :转义后相当于按退格键,但前提是“\\b”后面存在字符;“\\b”表示删除前一个字符,“\\b\\b”表示删除前两个字符。
\\c:不换行输出,在“\\c”后面不存在字符的情况下,作用相当于echo -n ,但是当“\\c”后面仍然存在字符时,“\\c”后面的字符将不会被输出。
\\n:换行,被输出的字符从“\\n”处开始另起一行。
\\f:换行,但是换行后的新行的开头位置连接着上一行的行尾;\\v\\f相同。
\\t 转义后表示插入tab,即横向制表符
\\r:光标移至行首,但不换行,相当于使用“\\r”以后得字符覆盖“\\r”之前同等长度的字符;但是当“\\r”后面不存在任何字符时,“\\r”前面的字符不会被覆盖。
\\:表示插入“\\”本身。
在这里插入图片描述
✪示例
1.通过输出转义子符实现磁盘分区
在这里插入图片描述
✪截取字符串

i=`echo "11,22,33, 44"`

echo ${i%,*}
11,22, 33
//从最后倒数到最短的匹配部分(%)后面的逗号的地方被删除

echo ${i%%,*}
l1
//从最后倒数到最长的匹配部分(%%)后面的逗号的地方都被删除

echo ${i#*, } 
22,33, 44
//从开头到最短的匹配部分(#)后面的逗号的地方被删除

echo ${i##*,}
44
//从开头到最长的匹配部分(##)后面的逗号的地方被删除

i=`echo “1234567890”`
echo ${i:3:4}
4567
//从第3位开始截取,第一位为0,截取4位,中间用“:”隔开

在这里插入图片描述

二.循环语句

1.for循环语句

读取不同的变量值,用来逐个执行同一组命令

for  变量名  in 取值列表							for 收件人  in  邮件地址列表
do												do
	命令序列												发送邮件
done											done

在这里插入图片描述
✪for循环的三种表达方式
❉第一种
在这里插入图片描述
❉第二种
在这里插入图片描述
❉第三种
在这里插入图片描述
✪示例
❉1.批量添加用户
用户名存放在user.txt文件中,每行一个
初始密码均为666

#!/bin/bash
USER=$(cat /scripts/user.txt)

for i in $USER
do
	useradd $i
	echo 666 |  passwd --stdin $i &> /dev/null
done

sh user.sh

在这里插入图片描述

❉2.根据IP地址检查主机状态
IP地址存放在ipadds.txt文件中,每行一个
使用ping命令检测各主机的连通性

vim  ip.sh

#!/bin/bash

IP=`cat /script/ipadds.txt`
for i in $IP
do
	ping -c 5 -i 0.2 -w  2 $i &> /dev/null
	if [ $? -eq 0 ]
	then 
		echo "$i主机存活"
	else
		echo "$i主机不存活"
	fi
done

sh ip.sh
	 

在这里插入图片描述

2.while语句的结构

重复测试某个条件,只要条件成立则反复执行

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

在这里插入图片描述
在这里插入图片描述

✪示例
❉1.批量添加用户
用户名称以stu开头,按数字顺序进行编号
一共添加20个用户,即stu1,stu2,……,stu20
初始密码均为666

vim 2.sh
#!/bin/bash
a=1
while [ $a -le 20]
do
	useradd stu$a
	echo 666 | passwd --stdin stu$a
	let a++
done

sh 2.sh
	

在这里插入图片描述
❉2.猜商品价格
通过变量RANDOM获得随机数
提示用户猜测并记录次数,猜中后退出循环

vim  3.sh
#!/bin/bash

ran=$[ $RANDOM % 1000 ]
a=1
b=0
while [ $a -lt  2 ]
do
        read  -p "请输入你猜的价格(1-999):" cai
        if [ $cai -eq $ran ]
        then
                echo "恭喜你你猜对了!"
                let b++
                let a++
        elif [ $cai -gt $ran ]
        then
                echo "你猜高了!"
                let b++
        elif [ $cai -lt $ran ]
        then
                echo "你猜低了!"
                let b++
        fi

done

	

在这里插入图片描述
在这里插入图片描述

3.until语句

重复测试某个条件,只要条件不成立则反复执行

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

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
✪示例
计算1-50的和值
通过循环累加的方式计算1-50的和值

在这里插入图片描述

三.终止循环

1.break跳出单个循环

#!/bin/bash

for ((a=1;a<=5;a++))
do
        echo  "外循环--------:a=$a"
        for ((b=1;b<=5 ;b++))
        do
                if [ $b -eq 3 ]
                then
                break
                fi
                echo  -e "\\t内循环-------:b=$b"				\\t为横向制表符
        done
done

在这里插入图片描述

2.continue中止某次循环中的命令,但不会完全中止整个命令

#!/bin/bash

for ((a=1;a<=5;a++))
do
        echo  "外循环--------:a=$a"
        for ((b=1;b<=5 ;b++))
        do
                if [ $b -eq 3 ]
                then
                continue
                fi
                echo  -e "\\t内循环-------:b=$b"
        done
done
                                 

在这里插入图片描述
示例
用户输入密码,脚本判断密码是否正确,输入正确提示提示正确信息,连续输错3次则报警

#!/bin/bash

ma=123456

for ((i=1;i<=3;i++))
do
        read -p "请输入密码:" a
        if [ $a -eq $ma ]
        then
                echo "密码输入正确!"
                exit
        else
                echo "密码输入错误,请再次输入"

        fi
done
echo "警告,密码错误3次。"

在这里插入图片描述

四.IFS字段分隔符

默认包含空格( ),制表符(\\t) ,换行符(\\n)  
set | grep IFS     查看IFS字段分隔符

在这里插入图片描述
示例
输出环境变量PATH所包含的所有目录以及其中的所有可执行文件

#!/bin/bash
#PATH所包含的所有目录以及其中的所有可执行文件

dz=$IFS
IFS=$IFS:
for i in $(echo $PATH)
do
		echo "PATH所包含的目录:" $i
        for a in $i/*
        do
            if [ -x $a ]
            then
                  echo "其中的可执行文件:" $a
            fi
            done
done
IFS=$dz

在这里插入图片描述

以上是关于Shell while循环语句中的陷阱的主要内容,如果未能解决你的问题,请参考以下文章

Shell编程Shell中for循环while循环until循环语句

shell之循环语句

Shell脚本------循环语句(for,while,until循环语句)

shell编程之case分支语句,for循环语句和while循环语句

shell脚本while循环语句

shell循环