变量

自定义变量

变量名遵循原则

  • 变量是由任何字母、数字和下划线组成的字符串,且不能以数字开头
  • 区分字母大小写,例如Var1和var2是不同的
  • 变量、等号、值中间不能出现任何空格

变量引用

  • var1=hello
  • echo $var1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@localhost ~]# var1=hello
[root@localhost ~]# echo $var1
hello
[root@localhost ~]# var_2=world
[root@localhost ~]# echo $var_2
world
[root@localhost ~]# echo $var1+$var_2
hello+world
[root@localhost ~]# 1var=jeck # 变量不能以数字开头
-bash: 1var=jeck: 未找到命令
[root@localhost ~]# var_a=123
[root@localhost ~]# Var_a=abc
[root@localhost ~]# echo $var_a
123
[root@localhost ~]# echo $Var_a
abc
[root@localhost ~]# var1 = 123 # 不能有空格
-bash: var1: 未找到命令

位置变量

  • 当一条命令或脚本执行时,后面可以跟多个参数,我们使用位置参数变量来表示这些参数

    1
    [root@localhost ~]# sh1.sh hello world 123 456

    位置参数变量

位置参数变量 含义
$n n为数字,$0代表脚本本身,$1$9代表19个参数,10以上的参数需要用大括号包含,如${10}
$@ 命令行所有参数,但每个参数区别对待
$* 命令行所有参数,所有参数视为一个整体
$# 参数个数

练习

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash

echo "The First Para: $1"
echo "The Second Para: $2"
echo "The Third Para: $3"
echo "The Fourth Para: $4"
echo "The Fifth Para: $5"

echo $*
echo $@
echo $#

运行结果

1
2
3
4
5
6
7
8
9
[root@localhost shell-script]# sh var_demo01.sh aaa 123 ccc 456
The First Para: aaa
The Second Para: 123
The Third Para: ccc
The Fourth Para: 456
The Fifth Para:
aaa 123 ccc 456
aaa 123 ccc 456
4
1
2
3
4
5
6
7
8
#!/bin/bash

function add {
value=`expr $1 + $2`
echo $value
}

add 123 456

运行结果

1
2
[root@localhost shell-script]# sh var_demo02.sh
579

环境变量

  • Linux是一个多租户的操作系统,针对不同的用户都会有一个专有的运行环境
  • 不同用户的专有环境就是一组默认环境变量的组合

注意:环境变量定义通常是全大写

环境变量分类

  • 对所有用户生效的环境变量:/etc/profile
  • 对特定用户生效的环境变量:~/.bashrc或者~/.bash_profile
  • 临时有效的环境变量:脚本或命令行使用export

常用环境变量

环境变量 含义
PATH 命令搜索的路径
HOME 用户家目录的路径
LONGAME 用户登录名
PWD 当前所在路径
HISTFILE 历史命令的保存文件
HISTSIZE 历史命令保存的最大行数
HOSTNAME 主机名
SHELL 用户当前使用的SHELL
PS1 以及命令提示符
TMOUT 用户和系统交互过程的超时值
IFS 系统输入分隔符
OFS 系统输出分隔符

变量生效

环境变量修改完成后,默认是不生效的,需要执行命令时环境变量生效:source 环境变量的文件

1
[root@localhost ~]# source /etc/profile

管道

思考一个小需求

  • 需求:将系统上所有软件包列出来,然后去搜索python相关的软件包
  • 解决方法:使用命令列出系统已有的所有软件包,然后把结果重定向到文件中,然后在文件中搜索python
  • rpm -qa > all_soft.txt,在利用vim去搜索python

使用管道来解决

  • 列出所有软件包,然后将结果传递给后续命令处理
  • rpm -qa | grep python

管道定义

  • 将一个命令的输出作为另一个命令的输入
  • 从某种意义上来说,是重定向的简易实现

退出状态码

  • 所有的shell命令都使用退出状态码来告诉shell它已执行完毕
  • 退出状态码是一个0~255的整数值
  • Linux提供了一个$?来捕获退出状态码的值

Linux退出状态码

状态码 含义
0 命令成功结束
1 一般性未知错误
2 不适合的shell命令
126 命令不可执行
127 没找到命令
128 无效的退出参数
128+x 与Linux信号x相关的严重错误
130 通过Ctrl+C终止的命令
255 正常范围之外的退出码

实践用法

状态码 含义
0 命令执行成功的情况
非0 不成功的情况

练习

1
2
3
4
5
6
7
8
#!/bin/bash

date
if [ $? -eq 0 ];then
echo "success..."
else
echo "failed..."
fi

运行结果

1
2
3
[root@localhost shell-script]# sh var_demo03.sh
2021年 02月 15日 星期一 08:05:46 CST
success...

例如:检测nginx的存在,目前本机未安装nginx

1
2
3
4
[root@localhost ~]# ps -ef | grep nginx
root 5436 3791 0 08:08 pts/0 00:00:00 grep --color=auto nginx
[root@localhost ~]# echo $?
0

本机未装nginx,但是我们在搜索进程的时候,尽然是成功的,这是因为ps在搜索进程的时候会有一个搜索nginx的子进程,因此会返回成功,而我们在搜索时,应需要把该子进程忽略

1
2
3
[root@localhost ~]# ps -ef | grep nginx | grep -v grep
[root@localhost ~]# echo $?
1

改变退出状态码的exit命令

  • 退出状态码是以上一条指令的返回结果为准
  • exit $exit_code
  • exit 48 或者 exit 125或者exit 0

练习

现在有如下脚本代码

1
2
3
4
5
6
7
8
9
10
#!/bin/bash

datess # 错误指令
if [ $? -eq 0 ];then
echo "success..."
else
echo "failed..."
fi

echo $?

运行结果

1
2
3
4
[root@localhost shell-script]# sh var_demo03.sh
var_demo03.sh:行3: datess: 未找到命令
failed...
0

我们看到运行结果是失败的,但是输出的$?依旧是0,下面的$?是指if-else中的指令是否执行成功,echo "failed..."是执行成功的,因此会返回成功的状态码,其实这是不符合我们需求的,我们预期的结果是失败的,下面我们需要修改退出状态码

1
2
3
4
5
6
7
8
9
#!/bin/bash

datess # 错误指令
if [ $? -eq 0 ];then
echo "success..."
else
echo "failed..."
exit 25
fi

判断与控制

if-then

语法

1
2
3
4
if command | condition
then
commands
fi

练习

1
2
3
4
5
6
#!/bin/bash

if pwd
then
echo "It works"
fi

运行结果

1
2
3
[root@localhost shell-script]# sh if_then.sh
/root/shell-script
It works

if-then-else

语法

1
2
3
4
5
6
if command | condition
then
commands
else
commands
fi

练习

1
2
3
4
5
6
7
8
#!/bin/bash

if ps -ef | grep mysql | grep -v grep
then
echo "MySQL is RUNNING"
else
echo "MySQL is STOP"
fi

运行结果,MySQL服务不存在的

1
2
[root@localhost shell-script]# sh if_then_else.sh
MySQL is STOP

注意:ps -ef | grep mysql | grep -v grep &> /dev/null 将指令的输出扔到垃圾桶中,但不影响指令执行,我们关心指令运行是否成功,不关心输出

嵌套if

语法

1
2
3
4
5
6
7
8
9
if command | condition
then
commands
elif command | condition
then
commands
else
commands
fi

练习

1
2
3
4
5
6
7
8
9
#!/bin/bash

if ps -ef | grep mysql | grep -v grep &> /dev/null;then
echo "MySQL is RUNNING"
elif ps -ef | grep httpd | grep -v grep &> /dev/null;then
echo "Apache HTTPD is RUNNING"
else
echo "MySQL and Apache HTTPD is all STOP"
fi

运行结果

1
2
[root@localhost shell-script]# sh if_then_else.sh
MySQL and Apache HTTPD is all STOP

实战:条件测试

数值比较

数值比较 含义
n1 -eq n2 n1和n2相等,则返回true;否则返回false
n1 -ne n2 n1和n2不相等,则返回true;否则返回false
n1 -gt n2 n1大于n2,则返回true;否则返回false
n1 -ge n2 n1大于等于n2,则返回true;否则返回false
n1 -lt n2 n1小于n2,则返回true;否则返回false
n1 -le n2 n1小于等于n2,则返回true;否则返回false
n1 -ne n2 n1不等于n2,则返回true;否则返回false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash

if [ $1 -eq $2 ]; then
echo "$1 = $2"
elif [ $1 -gt $2 ]; then
echo "$1 > $2"
elif [ $1 -ge $2 ]; then
echo "$1 >= $2"
elif [ $1 -lt $2 ]; then
echo "$1 < $2"
elif [ $1 -le $2 ]; then
echo "$1 <= $2"
elif [ $1 -ne $2 ]; then
echo "$1 != $2"
fi

执行结果

1
2
3
4
5
6
[root@localhost shell-script]# sh condition_demo01.sh 12 23
12 < 23
[root@localhost shell-script]# sh condition_demo01.sh 12 12
12 = 12
[root@localhost shell-script]# sh condition_demo01.sh 12 10
12 > 10

字符串比较

数值比较 含义
str1 = str2 相等比较
str1 != str2 不相等比较
str1 < str2 str1小于str2位true,注意:小于号与重定向符重复,使用时需要转义\<
str1 > str2 str1大于str2位true
-n str1 str1长度不是0则为true
-z str1 str1长度为0则为true
1
2
3
4
5
6
7
8
9
10
#!/bin/bash

var1="hello"
var2="world"

if [ $var1 \< $var2 ]; then
echo "<"
else
echo ">"
fi

执行结果

1
2
[root@localhost shell-script]# sh condition_demo02.sh
<
1
2
3
4
5
6
7
8
9
#!/bin/bash

var2="world"

if [ -n "$var1" ]; then
echo "var1 is not null"
else
echo "var1 is null"
fi

执行结果

1
2
[root@localhost shell-script]# sh condition_demo02.sh
var1 is null

文件比较

比较 含义
-d file file是否为目录
-f file file是否为文件
-e file file是否存在
-r file file是否可读
-w file file是否可写
-x file file是否可执行
-s file file存在且非空
file1 -nt file2 file1比file2新返回true
file1 -ot file2 file1比file2旧返回true
1
2
3
4
5
6
7
#!/bin/bash

if [ -d /usr/local/test ]; then
echo "yes"
else
echo "no"
fi

执行结果,test文件不存在

1
2
[root@localhost shell-script]# sh condition_file.sh
no

实战:复合条件测试

1
2
3
4
if condition1 && condition2
then
commands
fi
1
2
3
4
5
6
7
8
9
#!/bin/bash

var1=56
var2=34
var3=89

if [ $var1 -gt $var2 ] && [ $var2 -lt $var3 ]; then
echo "$var1 > $var2 并且 $var2 < $var3"
fi

执行结果

1
2
[root@localhost shell-script]# sh condition_demo04.sh
56 > 34 并且 34 < 89

if-then中使用双括号

使用双括号进行算术运算

  • 使用双括号可以进行算术运算,可以写类C语言的运算表达式
  • a++或者b–或者a+=1或者a<b或者a!=b

Condition使用双括号

1
2
3
4
if ((expression))
then
commands
fi

可用运算符

运算符 含义
value++ 后增
vaule– 后减
++value 先增
–value 先减
! 逻辑求反
== 相等
> 大于
< 小于
>= 大于等于
<= 小于等于
&& 逻辑与
|| 逻辑或

注意事项

  • 双括号结构中,变量名引用可以加$,也可以不加
  • 运算符前后可以有空格,也可以没有
  • 可以用于if、for、with等循环控制结构中
  • 多个运算符使用逗号分隔

练习

1
2
3
4
5
6
7
#!/bin/bash

if (( $1 > $2 && $3 > $2 ));then
echo "yes"
else
echo "no"
fi

运行结果

1
2
[root@localhost shell-script]# sh condition_demo05.sh 12 9 12
yes

If-then中使用双方括号

  • 使用双括号支持类C语言的条件测试

单方括号条件测试语言

1
2
3
4
if [ $n1 -gt $n2 ] && [$n2 -lt $n3]
then
commands
fi

双方括号条件测试语法

1
2
3
4
if [[ $n1 -gt $n2 && $n2 -lt $n3 ]]
then
commands
fi

注意事项

  • 双括号结构中,变量名引用必须加$
  • [[后面必须有空格,]]前面也必须有空格

练习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/bin/bash

a=$1
b=$2
c=$3

if [ $1 -gt $2 ] && [ $3 -gt $2 ];then
echo yes
else
echo no
fi

if [[ $a > $b && $b < $c ]];then
echo yes
else
echo no
fi

case命令

if语句写法

1
2
3
4
5
6
7
8
9
if(( a==1 ));then
commands
elif (( a==2 ));then
commands
elif (( a==5 ));the
commands
else
commands
fi

case语句语法

1
2
3
4
5
6
7
8
case $var in
pattern1)
commands
;;
pattern2)
commands
;;
esac

练习

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash

case $1 in
jack)
echo "hello jack"
;;
mike)
echo "hello mike"
;;
*)
echo "hello everyone"
;;
esac

执行结果

1
2
3
4
5
6
[root@localhost shell-script]# sh case_demo.sh jack
hello jack
[root@localhost shell-script]# sh case_demo.sh mike
hello mike
[root@localhost shell-script]# sh case_demo.sh lili
hello everyone

循环与控制

for循环命令

  • 循环遍历一系列特定值,然后在结构体中针对每个特定值做处理

语法

1
2
3
4
for var in list
do
commands
done

for循环读取列表的值

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash

for i in Beijing Shanghai Nanjing Guangzhou Suzhou Zhengzhou
do
echo "Province is $i"
done

for i in {01..10}
do
echo "Number is $i"
done

执行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@localhost shell-script]# sh for_demo01.sh
Province is Beijing
Province is Shanghai
Province is Nanjing
Province is Guangzhou
Province is Suzhou
Province is Zhengzhou
Number is 01
Number is 02
Number is 03
Number is 04
Number is 05
Number is 06
Number is 07
Number is 08
Number is 09
Number is 10

for循环读取变量的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash

# 默认输入分隔符--空格
list="Zhangsan Lisi Mike Tome"
for i in $list ; do
echo "Name is $i"
done

# 设置输入分隔符为--冒号:
IFS=":"
info="Mike:25"
for i in $info ; do
echo "Person info $i"
done

执行结果

1
2
3
4
5
6
7
[root@localhost shell-script]# sh for_demo02.sh
Name is Zhangsan
Name is Lisi
Name is Mike
Name is Tome
Person info Mike
Person info 25

for循环读取命令执行的结果值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/bin/bash

for i in $(ls /opt/)
do
if [ -d /opt/$i ]; then
echo "$i is DIR"
elif [ -f /opt/$i ]; then
echo "$i is FILE"
else
echo "error"
fi
done

# 改变系统默认输入分隔符
IFS=$'\n'
for i in $(cat a.txt) ; do
echo $i
done

执行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@localhost shell_script]# ll /opt/
总用量 0
drwx--x--x. 4 root root 28 2月 21 20:09 containerd
[root@localhost shell_script]# cat a.txt
shanghai
beijing
suzhou
hu nan
[root@localhost shell_script]# sh for_demo01.sh
containerd is DIR
shanghai
beijing
suzhou
hu nan

C语言风格的for命令用法

C语言中的for循环

1
2
3
4
for(i=0;i<10;i++)
do
printf("The next number is %d\n", i)
done

C语言风格的for循环语法

1
2
3
4
for((a=1;a<10;a++))
do
commands
done

练习

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash

for((i=0;i<10;i++))
do
echo "Next Number is:$i"
done

for((i=1;i<=100;i++))
do
(( sum+=$i ))
done

echo "1+2+3+...+100=$sum"

执行结果

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost shell_script]# sh for_demo02.sh
Next Number is:0
Next Number is:1
Next Number is:2
Next Number is:3
Next Number is:4
Next Number is:5
Next Number is:6
Next Number is:7
Next Number is:8
Next Number is:9
1+2+3+...+100=5050

while循环命令

while循环语法

1
2
3
4
while command
do
commands
done

练习

1
2
3
4
5
6
7
#!/bin/bash

num=10
while [ $num -lt 20 ]; do
echo "Number is $num"
((num++))
done

执行结果

1
2
3
4
5
6
7
8
9
10
11
[root@localhost shell_script]# sh while_demo.sh
Number is 10
Number is 11
Number is 12
Number is 13
Number is 14
Number is 15
Number is 16
Number is 17
Number is 18
Number is 19

until命令

until循环语法

1
2
3
4
until command
do
commands
done

练习

1
2
3
4
5
6
7
8
9
#!/bin/bash

num=10

# num=0时循环才会终止循环
until [ $num -eq 0 ]; do
echo "Number is $num"
((num--))
done

执行结果

1
2
3
4
5
6
7
8
9
10
11
[root@localhost shell_script]# sh until_demo.sh
Number is 10
Number is 9
Number is 8
Number is 7
Number is 6
Number is 5
Number is 4
Number is 3
Number is 2
Number is 1

控制循环的break命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash

for ((i=1;i<=10;i++));do
if ((i==5)); then
# 跳出整个for循环
break
fi
echo "$i"
done

for ((i=1;i<=10;i++));do
for (( j = 1; j <=5; j++ )); do
if ((j==3)); then
# break 数字 跳出几重循环,例如2 跳出2重循环
break 2
fi
echo "$i $j"
done
done

执行结果

1
2
3
4
5
6
7
[root@localhost shell_script]# sh break_demo.sh
1
2
3
4
1 1
1 2

控制循环的continue命令

1
2
3
4
5
6
7
8
#!/bin/bash

for ((i=10;i<30;i++));do
if ((i>15 && i<25)); then
continue
fi
echo "Number is $i"
done

执行结果

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost shell_script]# sh continue_demo.sh
Number is 10
Number is 11
Number is 12
Number is 13
Number is 14
Number is 15
Number is 25
Number is 26
Number is 27
Number is 28
Number is 29

处理循环的输出

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash

for ((i=1;i<100;i++));do
echo "Number is $i"
done > result.txt
# 将结果输出到result.txt文件中

for ((i=1;i<100;i++));do
echo "Number is $i"
done | grep "5"
# 管道处理结果