[ Content contribution] 基于deepin的shell编程-循环与处理用户输入
Tofloor
default avatar
天阁创客official
deepin
2023-12-29 17:43
Author

循环

7.1 for语句

与其他的编程语言一样,shell编程也支持循环语句。

语法

 for varlue in list  do   commands  done

第二种语法当然也可以直接在list后面加上一个;直接接上do。

 zql@zql-PC:~$ cat for1.sh  #!/bin/bash    echo "This is a simple for setence."  for name in Lisa Dave Phplip  do          echo "Hell0 $name!"  done  echo "Progame exit."  zql@zql-PC:~$ ./for1.sh  This is a simple for setence.  Hell0 Lisa!  Hell0 Dave!  Hell0 Phplip!  Progame exit.  zql@zql-PC:~$

读取列表里的复杂值

 zql@zql-PC:~$ ./for2.sh  这是一个复杂的列表读取.  Word:I  Word:Love  Word:?  Word:Whats your name? Iam  Word:is  Word:Lisa.  Progame exit.

sh源码

 zql@zql-PC:~$ cat for2.sh  #!/bin/bash  echo "这是一个复杂的列表读取." ; sleep 0.2  for value in I Love ? What's your name? I'am is Lisa.  do          echo "Word:$value"  done  echo "Progame exit."

发现他无法识别引号。它会把引号包括的内容和前后的字符进行输出。只有使用转义符\或者双引号来定义单引号的都内容。

修改后如下:

 zql@zql-PC:~$ ./for2.sh  这是一个复杂的列表读取.  Word:I  Word:Love  Word:?  Word:What's  Word:your  Word:name?  Word:I'am  Word:is  Word:Lisa.

注意:for循环各个值之间使用 空格隔开的,当值里面含有空格就麻烦了,必须使用双引号来将其空格输出

从变量中读取值

 zql@zql-PC:~$ ./for3.sh  读取变量例的值.  I love Name:Lisa.  I love ZhangFei.  I love XiaHouDun.  Progame exit.  zql@zql-PC:~$ cat for3.sh  #!/bin/bash    echo "读取变量例的值." ; sleep 0.2  namelist="Lisa ZhangFei XiaHouDun"  namelist="Name:"$namelist    for value in $namelist  do  echo "I love $value."  done  echo "Progame exit."

从命令中读取列表的值

 zql@zql-PC:~$ cat for4.sh  #!/bin/bash  echo "从命令中读取列表的值."  name="for1.sh"  for value in $(cat $name)  do          echo "value=$value"  done  echo "Progame exit."  zql@zql-PC:~$ ./for4.sh  从命令中读取列表的值.  value=#!/bin/bash  value=echo  value="This  value=is  value=a  value=simple  value=for  value=setence."  value=for  value=name  value=in  value=Lisa  value=Dave  value=Phplip  value=do  value=echo  value="Hell0  value=$name!"  value=done  value=echo  value="Progame  value=exit."  Progame exit.

更改字段分隔符

若要修改空格、制表符、换行符作为shell的字段分隔符,就必须要用到IFS,IFS是特殊的环境变量,用来定义内部字段的分隔符。如果只想让换行符作为为能够识别的分隔符只需要把\n加入IFS中即可。

 zql@zql-PC:~$ ./for5.sh  更改分隔符为只换行符.  value=#!/bin/bash  value=echo "This is a simple for setence."  value=for name in Lisa Dave Phplip  value=do  value=  echo "Hell0 $name!"  value=done  value=echo "Progame exit."  Progame exit.      zql@zql-PC:~$ cat for5.sh  #!/bin/bash    file="for1.sh"  echo "更改分隔符为只换行符."  IFS=$'\n'  for value in $(cat $file)  do          echo "value=$value"  done  echo "Progame exit."

注意:在写大量脚本的时候,需要IFS的值进行保存恢复

保存IFS值,便于恢复

 IFS.OLD=$IFS    IFS=#"\n"

定义新的IFS值

 IFS=$IFS.OLD

通配符读取目录

使用for循环来遍历目录,利用通配符的特点来实现。

 zql@zql-PC:~$ ./for6.sh  /var/account is a directory.  /var/adm is a directory.  /var/cache is a directory.  /var/crash is a directory.  /var/db is a directory.  /var/empty is a directory.  /var/ftp is a directory.  /var/games is a directory.  /var/kerberos is a directory.  /var/lib is a directory.  /var/local is a directory.  /var/lock is a directory.  /var/log is a directory.  /var/mail is a directory.  /var/nis is a directory.  /var/opt is a directory.  /var/preserve is a directory.  /var/run is a directory.  /var/spool is a directory.  /var/tmp is a directory.  /var/www is a directory.  /var/yp is a directory.    zql@zql-PC:~$ cat for6.sh  #!/bin/bash  for file in /var/*  do          if [ -d "$file" ]          then echo "$file is a directory."          elif [ -f "$file" ]          then "$file is a file."          fi  done

7.2 C风格的for语句

语法

 for (( variable assignment ; condition ; iteration process ))

注意:

  • 变量赋值可以有空格。
  • 迭代条件中的变量不以美元符号开头。
  • 迭代过程的算式不使用expr命令格式。

 zql@zql-PC:~$ ./for7.sh  Number: --1  Number: --2  Number: --3  Number: --4  Number: --5  Number: --6  Number: --7  Number: --8  Number: --9  Number: --10  zql@zql-PC:~$ cat for7.sh  #!/bin/bash    for (( i=1; i <= 10; i++ ))  do          echo "Number: --$i"  done  

多变量循环

 #!/bin/bash  # multiple variables    for (( a=1, b=10; a <= 10; a++, b-- ))  do     echo "$a - $b"  done  zql@zql-PC:~$ ./for9.sh  1 - 10  2 - 9  3 - 8  4 - 7  5 - 6  6 - 5  7 - 4  8 - 3  9 - 2  10 - 1

7.3 while语句

**while命令在某种程度上糅合了if-then语句和for循环。while命令允许定义一个要测试的命令,只要该命令****返回的退出状态码为0,就循环执行一组命令。它会在每次迭代开始时测试test命令,如果test命令返回非0退出状态码,while命令就会停止执行循环。**一直为0就是死循环。

语法

 while test command  do   other commends  done

 zql@zql-PC:~$ ./while1.sh  10  9  8  7  6  5  4  3  2  1  zql@zql-PC:~$ cat while1.sh  #!/bin/bash    var1=10  while [ $var1 -gt 0 ]  do          echo $var1          var1=$[ $var1 -1 ]  done

多个测试命令

while命令允许在while语句行定义多个测试命令。只有最后一个测试命令的退出状态码会被用于决定是否结束循环。

 zql@zql-PC:~$ ./while2.sh  10  这是循环的内部.  9  这是循环的内部.  8  这是循环的内部.  7  这是循环的内部.  6  这是循环的内部.  5  这是循环的内部.  4  这是循环的内部.  3  这是循环的内部.  2  这是循环的内部.  1  这是循环的内部.  0  这是循环的内部.  -1  zql@zql-PC:~$ cat while2.sh  #!/bin/bash    value=10  while echo $value         [ $value -ge 0 ]  do          echo "这是循环的内部."          value=$[ $value -1 ]  done

以上表明当在含有多个命令的while语句中,每次迭代都会被执行,包括最后一个执行命令失败的末次迭代。

7.4 untile

与while命令工作的方式完全相反,until命令要求指定一个返回非0退出状态码的测试命令。只要测试命令的退出状态码不为0,bash shell就会执行循环中列出的命令。一旦测试命令返回了退出状态码0,循环就结束了。

 until test commands  do     other commands  done

 zql@zql-PC:~$ ./until1.sh  5  4  3  2  1  zql@zql-PC:~$ cat until1.sh  #!/bin/bash    value=5  until [ $value -eq 0 ]  do          echo $value          value=$[ $value - 1 ]  done  

与while语句一样,until语句多命令的时候每次迭代都会被执行,包括最后一个执行命令失败的末次迭代。

7.5 嵌套循环与文件数据

嵌套循环

循环的时候嵌套其他的语句就是嵌套循环,until与while也是可以嵌套在一起的。

注意:在使用嵌套的时候是在迭代中迭代,命令运行的次数是乘积关系。

 zql@zql-PC:~$ ./forfor.sh  外层循环1:  内循环:1  内循环:2  内循环:3  外层循环2:  内循环:1  内循环:2  内循环:3  外层循环3:  内循环:1  内循环:2  内循环:3  zql@zql-PC:~$ cat forfor.sh  #1/bin/bash    for (( a = 1; a <= 3; a++ ))  do          echo "外层循环$a:"          for (( b = 1; b <=3; b++ ))          do                  echo "内循环:$b"          done  done

until与while循环嵌套

 $ cat test16  #!/bin/bash  # using until and while loops    var1=3    until [ $var1 -eq 0 ]  do     echo "Outer loop: $var1"     var2=1     while [ $var2 -lt 5 ]     do        var3=$(echo "scale=4; $var1 / $var2" | bc)        echo "   Inner loop: $var1 / $var2 = $var3"        var2=$[ $var2 + 1 ]     done     var1=$[ $var1 - 1 ]  done  $ ./test16  Outer loop: 3     Inner loop: 3 / 1 = 3.0000     Inner loop: 3 / 2 = 1.5000     Inner loop: 3 / 3 = 1.0000     Inner loop: 3 / 4 = .7500  Outer loop: 2     Inner loop: 2 / 1 = 2.0000     Inner loop: 2 / 2 = 1.0000     Inner loop: 2 / 3 = .6666     Inner loop: 2 / 4 = .5000  Outer loop: 1     Inner loop: 1 / 1 = 1.0000     Inner loop: 1 / 2 = .5000     Inner loop: 1 / 3 = .3333     Inner loop: 1 / 4 = .2500  $    #该段代码来源于:Linux命令行与shell脚本编程大全

处理数据

遍历文件中保存的数据,利用iFS和循环嵌套来实现。通过修改IFS环境变量,能强制for命令将文件中的每一行都作为单独的条目来处理,即便数据中有空格也是如此。从文件中提取出单独的行后,可能还得使用循环来提取行中的数据。

 zql@zql-PC:~$ cat No1.sh  #!/bin/bash  IFS.OLD=$IFS  IFS=$'\n'  for file in $(cat /etc/passwd)  do          echo "Values in $file ---"          IFS=:          for value in $file          do                  echo "  $value"          done  done    zql@zql-PC:~$ ./No1.sh  Values in root:x:0:0:root:/root:/bin/bash ---   root   x    0    0   root   /root   /bin/bash  Values in bin:x:1:1:bin:/bin:/sbin/nologin ---   bin   x    1    1   bin   /bin   /sbin/nologin

7.6 循环控制

使用break和continue可以直接退出循环。

二者的区别就是break是直接跳出循环(内、外、单个),而continue是跳出某次循环。

 #break跳出单个循环  #!/bin/bash  # breaking out of a for loop    for var1 in 1 2 3 4 5 6 7 8 9 10  do     if [ $var1 -eq 5 ]     then       break     fi     echo "Iteration number: $var1"  done  echo "The for loop is completed"  $ ./test17  Iteration number: 1  Iteration number: 2  Iteration number: 3  Iteration number: 4  The for loop is completed      #continue跳出某次循环  #!/bin/bash  # using the continue command    for (( var1 = 1; var1 < 15; var1++ ))  do     if [ $var1 -gt 5 ] && [ $var1 -lt 10 ]     then       continue     fi     echo "Iteration number: $var1"  done  $ ./test21  Iteration number: 1  Iteration number: 2  Iteration number: 3  Iteration number: 4  Iteration number: 5  Iteration number: 10  Iteration number: 11  Iteration number: 12  Iteration number: 13  Iteration number: 14    #该段代码来源于:Linux命令行与shell脚本编程大全

break结束外层循环语法

 break n

continue语法

 continue n

处理用户输入

参数传递与参数读取

bash shell会将所有的命令行的参数指向位置参数。

什么是位置参数,$0对应的是脚本名字,一次类推到9.

 zql@zql-PC:~$ ./inputnumber.sh 5  5的乘阶是120...  Progame exit.  zql@zql-PC:~$ ./inputnumber.sh 10  10的乘阶是3628800...  Progame exit.    zql@zql-PC:~$ cat inputnumber.sh  #!/bin/bash  #传递参数与参数的读取  a=1  #注意这里将常量number改为了一个变量$1  for (( number = 1; number <= $1; number++ ))  do          a=$[ $a * $number ]  done  sleep 0.2  echo "$1的乘阶是$a..." ; sleep 0.2  echo "Progame exit."  exit  

字符串也是可以传递进去的

 zql@zql-PC:~$ ./inputstring.sh World  Hello World!    zql@zql-PC:~$ cat inputstring.sh  #!/bin/bash  #传递字符串  echo "Hello $1!"  exit

8.1 读取脚本名

使用位置变量$0获取命令行中运行的shell脚本名。

 zql@zql-PC:~$ ./readsh.sh  This is name is ./readsh.sh    zql@zql-PC:~$ cat readsh.sh  #!/bin/bash  #读取脚本名  echo "This is name is $0"  exit

注意:命令会和脚本名混合在一起,出现在$0中。

8.2 统计参数

使用$#可以统计参数

 ┌──(zql㉿kali)-[~/sh]  └─$ ./concat.sh Hello  参数统计  1 parameter was supplied    ┌──(zql㉿kali)-[~/sh]  └─$ ./concat.sh Hello World  参数统计  2 parameters were supplied    ┌──(zql㉿kali)-[~/sh]  └─$ ./concat.sh Hello World !  参数统计  3 parameters were supplied    ┌──(zql㉿kali)-[~/sh]  └─$ cat concat.sh  #!/bin/bash  #  echo "参数统计"  if [ $# -eq 1 ]  then          fragment="parameter was"  else          fragment="parameters were"  fi  echo $# $fragment supplied

8.3 获取所有的数据

$加上*或@可以轻松访问所有参数。

 ┌──(zql㉿kali)-[~/sh]  └─$ ./anydata.sh 1234567  获取所有的数据    Using the $* method: 1234567    Using the $@ method: 1234567      ┌──(zql㉿kali)-[~/sh]  └─$ ./anydata.sh I love You !  获取所有的数据    Using the $* method: I love You !    Using the $@ method: I love You !      ┌──(zql㉿kali)-[~/sh]  └─$ cat anydata.sh  #!/bin/bash  #  echo "获取所有的数据"  echo  echo "Using the \$* method: $*"  echo  echo "Using the \$@ method: $@"  echo  exit

两者的区别

 ┌──(zql㉿kali)-[~/sh]  └─$ ./anydata.sh I love You !  获取所有的数据    Using the $* method: I love You !  $ Parameter #1 =    Using the $@ method: I love You !  \@ Parameter #1 = I  \@ Parameter #2 = love  \@ Parameter #3 = You  \@ Parameter #4 = !      ┌──(zql㉿kali)-[~/sh]  └─$ cat anydata.sh  #!/bin/bash  #  echo "获取所有的数据"  echo  echo "Using the \$* method: $*"  count=1  for parm in "$*"  do          echo "\$ Parameter #$count = $param"          count=$[ $count + 1 ]  done  echo  echo "Using the \$@ method: $@"  count=1  for param in "$@"  do          echo "\@ Parameter #$count = $param"          count=$[ $count + 1 ]  done  echo  exit
Reply Favorite View the author
All Replies
兆兆嘟嘟嘟
deepin
2023-12-29 19:59
#1

后面部分在Kali下运行?

Reply View the author
天阁创客official
deepin
2023-12-29 20:10
#2
It has been deleted!
天阁创客official
deepin
2023-12-29 20:13
#3
兆兆嘟嘟嘟

后面部分在Kali下运行?

当时写的时候因为是通过ssh连接deepin写的,在Windows终端上也连接了kali,可能写的时候选错终端栏了

Reply View the author
天阁创客official
deepin
2023-12-29 20:14
#4
兆兆嘟嘟嘟

后面部分在Kali下运行?

kali和deepin都是基于Debian开发的,能直接在deepin上运行的,shell编程本质就是通用的,一种命令行编程语言,所以系统影响不大,我在centos、kylin、Raspberry上一样能运行

Reply View the author
天阁创客official
deepin
2023-12-29 20:17
#5
天阁创客official

kali和deepin都是基于Debian开发的,能直接在deepin上运行的,shell编程本质就是通用的,一种命令行编程语言,所以系统影响不大,我在centos、kylin、Raspberry上一样能运行

当然有些细节上可能不太一样,因为大多是Linux都是BASH、kali是ZSH,大部分情况都是通用的,你可以试一试,同样的代码在不同的Linux上面运行,基本上是能够完全运行的,但是调用BASH的时候可能不行,因为不同的Linux有点区别嘛

Reply View the author