Skip to content

LV060-语句

本文主要是 shell——运算符和语句相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正 😃。

一、说明性语句

其实就是注释,以 # 号开始到该行结束,不被解释执行。 sh 里没有多行注释,只能每一行加一个#号。

shell
#--------------------------------------------
# 这是一个注释
# author:
# file name:
# description:
#--------------------------------------------

二、功能性语句

1. readonly

shell
readonly Variable # Variable 为变量名称

使用 readonly 命令可以 将变量定义为只读变量,只读变量的值不能被改变。

2. unset

shell
unset Variable # Variable 为变量名称

该命令可以删除已经定义的变量。

3. read

3.1 使用格式

read 用来从标准输入中读取数据并赋值给变量。如果没有进行重定向,默认就是从键盘读取用户输入的数据;如果进行了重定向,那么可以从文件中读取数据。

shell
read [option] [Variables]
[option] -a array 把读取的数据赋值给数组 array,从下标 0 开始
-d delimiter 用字符串 delimiter 指定读取结束的位置,而不是一个换行符(默认结束符号为换行符,读取到的数据不包括 delimiter)。
-n num 读取 num 个字符就结束,而不是整行字符。如果没有读满 num 个字符就按下回车或遇到换行符,则也会结束读取。
-N num 严格要求读满 num 个字符才自动结束读取,即使中途按下了回车或遇到了换行符也不结束,其中换行符或回车算一个字符。
-p prompt 显示提示信息,提示内容为 prompt。默认不支持 "\n" 换行,要换行需要特殊处理(例如:通过 $'string \n' 就可以实现换行输入)
-t timeout 设置超时时间,单位为秒。如果用户没有在指定时间内输入完成,那么 read 将会返回一个非 0 的退出状态,表示读取失败,即使已经输入了一部分。
-u fd 使用文件描述符 fd 作为输入源,而不是标准输入,类似于重定向。
-e 在输入的时候可以使用命令补全功能(Tab 键)。
-r 原样读取(Raw mode),不把反斜杠字符解释为转义字符,这意味着 "\" 会变成文本的一部分。
-s 静默模式(Silent mode),不会在屏幕上显示输入的字符。可用于输入密码和其它确认信息的时候。
[Variables] 变量名称
【**注意**】

(1)可以使用多个参数。

(2)变量读取说明

shell
read [-ers] [-a aname] [-d delim] [-i text] [-n num] [-N num] [-p prompt] [-t timeout] [-u fd] [var_name1 var_name2 ...]

首先说一下 IFS(internal field separator ,为 内部字段分隔符,是 bash shell 中的环境变量,它定义了 bash shell 用作字段分隔符的一系列字符,默认情况下, bash shell 会将下列字符当做字段分隔符:空格制表符换行符

read 命令用于从标准输入中读取输入单行,并将读取的单行根据 IFS 环境变量分裂成多个字段,并将分割后的字段分别赋值给指定的变量列表 var_name 。第一个字段分配给第一个变量 var_name1 ,第二个字段分配给第二个变量 var_name2 ,依次到结束。如果指定的变量名少于字段数量,则多出的字段数量也同样分配给最后一个 var_name ,如果指定的变量命令多于字段数量,则多出的变量赋值为空。如果没有指定任何 var_name ,则分割后的所有字段都存储在环境变量 REPLY 中。

3.2 使用实例

shell
#!/bin/bash
read -p $'Enter your name: \n'
echo $REPLY

运行结果:

shell
Enter your name: 
qidaink
qidaink

(3)给多个变量赋值时,必须在一行内输入所有的值,不能换行,否则只能给第一个变量赋值,后续变量都会赋值失败。

4. test

test 命令用于 检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试。通常和 if 语句一起使用,并且大部分 if 语句都依赖 test 。

以下只为举例说明使用格式,还有一些运算符可以查看本篇笔记的《运算符》。

4.1 数值测试

shell
test $[num1] <关系运算> $[num2]
运算符 -eq 等于,则为真
-ne 不等于,则为真
-gt 大于,则为真
-ge 大于等于,则为真
-lt 小于,则为真
-le 小于等于,则为真

4.2 字符串测试

shell
test $[num1] <字符串运算> $[num2]
运算符 = 等于,则为真
!= 不等于,则为真
-z 字符串 字符串的长度为零,则为真
-n 字符串 字符串的长度不为零,则为真

4.3 文件测试

shell
test <文件测试运算> file_name
运算符 -e file 如果文件存在,则为真
-f file 如果文件存在且可读,则为真

5. echo

5.1 使用格式

echo 用于在屏幕上打印出指定的字符串,命令格式如下:

shell
echo [option] string
-n 禁止在最后自动换行
-e 开启转义字符功能,即遇到以下字符进行处理,而不会将其当成一般字符输出
\a 警报,响铃
\b 退格(删除键)
\f 换页(FF),将当前位置移到下页开头
\n 换行
\c 不换行
\r 回车
\t 水平制表符(tab 键)
\v 垂直制表符
\ooo 插入 ooo(八进制)所代表的 ASCII 字符
\\ 反斜杠
--version 显示版本信息
--helo 显示帮助
【**注意**】该命令不带参数时 **自带换行**。

5.2 使用实例

5.2.1 显示普通字符串
shell
#!/bin/bash
echo "string1"
echo "string2"
echo string3

运行结果:

shell
string1
string2
string3
5.2.2 显示转义字符
shell
#!/bin/bash
echo "\"string\""
echo \"string\"

运行结果:

shell
"string"
"string"
5.2.3 显示变量
shell
#!/bin/bash
name=qidaink
echo $name
echo "$name"
echo "${name}"

运行结果:

shell
qidaink
qidaink
qidaink
5.2.4 显示换行与不换行
shell
#!/bin/bash
name=qidaink
echo -e "$name\nString1" # 开启转义字符,\n 换行
echo  "$name\nString1"

echo -e "$name\c"        # 开启转义字符,\c 不换行
echo "String2"

运行结果:

shell
qidaink
String1
qidaink\nString1
qidainkString2
5.2.5 显示结果定向至文件
shell
#!/bin/bash
name=qidaink
echo -e "$name\nString1" > file.txt

运行结果:会在当前 Shell 脚本所在目录创建一个 filt.txt 文件(无该文件的话),并将要显示的内容显示在 filt.txt 文件中。

5.2.6 原样输出字符串
  • 原样输出字符串,不进行转义或取变量(用单引号)
shell
#!/bin/bash
name=qidaink
echo "$name\nString1"
echo '$name\nString1'

运行结果:

shell
qidaink\nString1
$name\nString1
5.2.7 显示命令执行结果
shell
#!/bin/bash
echo  date 
echo 'date'
echo "date"

运行结果:

shell
2022年 02月 14日 星期一 13:29:17 CST
date
date

6. printf

6.1 使用格式

printf 由 POSIX 标准所定义,因此使用 printf 的脚本比使用 echo 移植性好。 printf 使用 引用文本或空格分隔 的参数,外面可以在 printf 中使用格式化字符串,还可以制定字符串的宽度、左右对齐方式等。默认的 printf 不会像 echo 自动添加换行符。使用格式如下:

shell
printf  "format-string>"  [arguments...]

其中 format-string 为格式控制字符串, arguments 为参数列表。 Shell 脚本中的 printf 和 C 语言中的 printf 用法基本一致,只是在写法上有些许区别。

  • printf 命令不用加括号
  • format-string 可以没有引号,但最好加上,单引号双引号均可。
  • 参数多于格式控制符( % )时, format-string 可以重用,可以将所有参数都转换。
  • arguments 使用 空格分隔,不用逗号。

6.2 转义字符

\a 警报,响铃
\b 退格(删除键)
\c 不显示输出结果中任何结尾的换行字符,而且任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符都被忽略。
\f 换页(FF),将当前位置移到下页开头
\n 换行
\r 回车
\t 水平制表符(tab 键)
\v 垂直制表符
\ooo 插入 ooo(八进制)所代表的 ASCII 字符
\\ 反斜杠字符

6.3 格式控制字符串

6.3.1 格式控制字符
格式字符 形式 意义
i, d %i, %d 以十进制形式输出带符号整数(正数不输出符号)
u %u 以十进制形式输出无符号整数
o %o 以八进制形式输出无符号整数(不输出前缀 0)
x, X %x, %X 以十六进制形式输出无符号整数(不输出前缀 0x)
f %f 以小数形式输出单、双精度实数
e, E %e, %E 以指数形式输出单、双精度实数
g, G %g, %G 以 %f 或 %e 中较短的输出宽度输出单、双精度实数
c %c 输出单个字符
s %s 输出字符串
6.3.2 标识
标识 描述
- 在给定的字段宽度内左对齐,默认是右对齐
+ 强制在结果之前显示加号或减号(+ 或 -),即正数前面会显示 + 号。默认情况下,只有负数前面会显示一个 - 号。
space
(空格)
有符号值若为正,则在值前显示前导空格(但是不显示符号);若为负,则在值前显示-。
# 与 o、x 或 X 说明符一起使用时,非零值前面会分别显示 0、0x 或 0X。
与 e、E 和 f 一起使用时,会强制输出包含一个小数点,即使后边没有数字时也会显示小数点。默认情况下,如果后边没有数字时候,不会显示显示小数点。
与 g 或 G 一起使用时,结果与使用 e 或 E 时相同,但是尾部的零不会被移除。
0 输出数值时指定左面不使用的空位置自动填 0。
6.3.3 最小输出宽度( width )
宽度 描述
number 数值(十进制整数),数据长度 小于 number,则左补空格;否则按实际输出。
* 星号,精度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格式化的参数之前。
6.3.4 精度( .precision )
精度 描述
.number 对于整数说明符(d、i、o、u、x、X):precision 指定了要写入的数字的最小位数。如果写入的值短于该数,结果会用前导零来填充。如果写入的值长于该数,结果不会被截断。精度为 0 意味着不写入任何字符。
对于 e、E 和 f 说明符:要在小数点后输出的小数位数。
对于 g 和 G 说明符:要输出的最大有效位数。
对于 s : 要输出的最大字符数, 不足 number 则正常输出,超过则截断。默认情况下,所有字符都会被输出,直到遇到末尾的空字符。
对于 c 类型:没有任何影响。
当未指定任何精度时,默认为 1。如果指定时不带有一个显式值,则假定为 0。
.* 星号,精度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格式化的参数之前。
但是在尝试的时候似乎有一些数据类型不匹配的情况,不过也用的不多。

6.4 使用实例

shell
#!/bin/bash
printf "%-10s %-8s %-4s\n" name sex kg  
printf "%-10s %-8s %-4.1f\n" qidai 72.162
printf "%-10s %-8s %-4.1f\n" fanhua 60.9612
printf "%-10s %-8s %-4.1f\n" yunyuhai 48.96313141

三、结构性语句

结构性语句主要根据程序的运行状态、输入数据、变量的取值、控制信号以及运行时间等因素来控制程序的运行流程。主要包括:条件测试语句(两路分支)、多路分支语句、循环语句、循环控制语句和后台执行语句等。

1. 分支语句

1.1 if...else... 语句

1.1.1 使用格式 1
  • 语法结构 1
shell
# if ... fi 结构
if [ expression ]
then
   Statement(s) to be executed if expression is true
fi

# 或者
if [ expression ] ; then
   Statement(s) to be executed if expression is true
fi

# 或者写成一行
if [ expression ] ; then Statement(s) to be executed if expression is true; fi;
1.1.2 使用格式 2
  • 语法结构 2
shell
# if ... else ... fi 结构
if [ expression ]
then
   Statement(s) to be executed if expression is true
else
   Statement(s) to be executed if expression is not true
fi
1.1.3 使用格式 3
  • 语法结构 3
shell
# if ... elif ... fi 结构
if [ expression 1 ]
then
   Statement(s) to be executed if expression 1 is true
elif [ expression 2 ]
then
   Statement(s) to be executed if expression 2 is true
elif [ expression 3 ]
then
   Statement(s) to be executed if expression 3 is true
else
   Statement(s) to be executed if no expression is true
f

【注意】

(1)以上三种结构中, if 和 elif 之后要跟一个 then ,结束要有 fi ,中间的执行语句不需要像 C 语言 一样有 {} 。

(2) then 可以与 if 或者 elif 写在同一行,但是要加一个 ;

(3) if 也常与 test 命令一起使用。

1.2 case 语句

1.2.1 使用格式
shell
casein
    模式1)
        command1
        command2
        command3
        ;;
    模式2)
        command1
        command2
        command3
        ;;
    *)
        command1
        command2
        command3
        ;;
esac

注意

(1)取值后面必须为单词 in ,每一模式必须以右括号结束。取值可以为变量或常数,匹配发现取值符合某一模式后,其间所有命令开始执行直至 ;; 。

(2)每个 case 分支用 右圆括号 开始,用两个分号 ;; 表示 break ,即执行结束。如果没有匹配到任何一个模式,使用星号 * 捕获该值,再执行后面的命令。

(3) esac (就是 case 反过来)作为整个结构结束标记。

1.2.2 使用实例
shell
#!/bin/bash

read -p "Inter a number:" value
if [ $value -lt 0 ] || [ $value -gt 100 ]
    then
    echo "input error."
    exit 0
else
    value= expr $value / 10 
    case $value in 
        8 | 9 | 10)
            echo  "A"
            ;;
        6 | 7)
            echo  "B"
            ;;
        *)
            echo  "C"
            ;;
    esac
fi

2. 循环语句

2.1 for 循环

2.1.1 使用格式 1
  • 语法结构 1
shell
for 变量 in 列表
do
    command1
    command2
    ...
    commandN
done
2.1.2 使用格式 2
  • 语法结构 2
shell
for((表达式1; 表达式2; 表达式2))
do
    command1
    command2
    ...
    commandN
done

【注意】

(1)以上两种结构都可以,但是都要注意不可省略 do 和 done 。

2.1.3 使用实例
shell
#!/bin/bash
printf "\033[31m shell方式 \033[0m\n"
for value in 1 2 3 4 5
    do
        printf "$value"
    done
    echo ""

printf "\033[31m 类似C语言方式 \033[0m\n"
for ((val = 1; val <=5; val++))
    do
        printf "$val"
    done
    echo ""

2.2 while 循环

2.2.1 使用格式 1
  • 语法结构 1
shell
while [ expression ]
do
   Statement(s) to be executed if expression is true
done
2.2.2 使用格式 2
  • 语法结构 2
shell
while (( expression )) 
do
   Statement(s) to be executed if expression is true
done
2.2.3 使用实例
shell
#!/bin/bash
# 语法结构 1 例子
i=1
sum=0
while [ $i -le 10 ]
do
	sum= expr $sum + $i 
	i= expr $i + 1 
done
echo "i = $i  sum = $sum"

# 语法结构 2 例子
num=0
while (( $num < 5))
do
	echo "$num"
	num= expr $num + 1 
done
echo "num=$num"

2.3 until 循环

until 循环执行一系列命令直至条件为 true 时停止。 until 循环与 while 循环在处理方式上刚好相反。一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下, until 循环更加有用。

2.3.1 使用格式
  • 语法结构
shell
until [ expression ]
do
   Statement(s) to be executed until command is true
done
2.3.2 使用实例
shell
#!/bin/bash
num=0
until [ ! ${num} -lt 3 ]
do
   echo ${num}
   num= expr ${num} + 1 
done

2.4 无限循环写法

2.4.1 for
shell
# for 写法
for (( ; ; ))
do
    command
done
2.4.2 while
shell
# while 写法 1
while :
do
    command
done

# while 写法 2
while true
do
    command
done

2.5 跳出循环

2.5.1 使用格式

在循环过程中,有时候需要在未达到循环结束条件时强制跳出循环, Shell 与 C 语言一致,使用两个命令来实现该功能: break 和 continue 。用法与 C 语言一致。

注意

(1)一般来说 break 是跳出本层循环, continue 是结束本次循环,直接进入下一次循环。

(2)在嵌套循环中, break 命令后面还可以跟一个整数,表示跳出第几层循环。 continue 后边也可以跟一个整数,表示继续第几层循环。

shell
break n      # break 所在循环层为第 1 层,然后再向外计算层数
continue n   # continue 所在循环层为第 1 层,然后再向外计算层数
2.5.2 使用实例
shell
#!/bin/bash
for var1 in 1 2
do
   echo "第1层循环 var1=${var1}"
   for var2 in 3 4
   do
      echo -e "\t第2层循环 var2=${var2}"
      for var3 in 5 6
      do
         if [ ${var1} == 1 ] && [ ${var2} == 4 ] && [ ${var3} == 5 ]
         then
            echo -e "break 跳出"
            break 3
         elif [ ${var1} == 1 ] && [ ${var2} == 3 ] && [ ${var3} == 5 ]
         then
            echo -e "continue 继续"
            continue 3
         fi
            echo -e "\t\t第3层循环 var3=${var3}"
            echo -e "\t\t一次循环结束 ${var1} ${var2} ${var3}"
      done
   done
done

四、三目运算符?

1. 使用格式

我也不知道叫啥,其实就很类似于条件语句:

shell
command1 && command2 || command3

command1 && { command2_1; command2_2; command2_3;} || { command3_1; command3_3; command3_3;}

2. 使用实例

shell
# fileName 文件不存在,则退出,就可以按照下面方式执行
[ -e $fileName ] || { echo -e "fileName Not existed!"; exit 1; }

#也或者可以增加一些 log 打印信息
[ -e $fileName ] && echo -e "$fileName existed" || { echo -e "$fileName Not existed!"; exit 1; }

#多个命令集合的组合
[ -e $fileName ] && echo -e "$fileName existed"; ehco -e "Other Necessary Information" || { echo -e "$fileName Not existed!"; exit 1; }
[ -e $fileName ] && { echo -e "$fileName existed"; ehco -e "Other Necessary Information"; } || { echo -e "$fileName Not existed!"; exit 1; }

#读取 IP 地址,若为空,则使用默认 IP,否则使用新的 IP 地址
read -p "Please input Management IP (Default is $DEFAULT_IP): " MGMT_IP 
[[ -z $MGMT_IP ]] && { MGMT_IP=$DEFAULT_IP; echo -e "Using default IP $MGMT_IP\n" ;} || DEFAULT_IP=$MGMT_IP