SHELL编程-Linux自动化运维基础(变量与条件控制语法)

SHELL编程-Linux自动化运维基础

变量使用

定义与使用

r123@localhost:~$ first_var=aaa
r123@localhost:~$ echo $first_var
aaa
r123@localhost:~$ second_var=123
r123@localhost:~$ echo $second_var
123
r123@localhost:~$ third="bbb ccc"
r123@localhost:~$ echo $third
bbb ccc
  • 定义变量时,变量名不能以数字开头,等号两侧不能出现空格,有空格的变量内容,必须以引号包含
  • 使用变量时必须加上$

拼接变量

r123@localhost:~$ first_var=123
r123@localhost:~$ first_var=${first_var}456
r123@localhost:~$ echo $first_var
123456
r123@localhost:~$ first_var="$first_var"789
r123@localhost:~$ echo $first_var
123456789

查看变量

直接使用set命令将输出目前shell中存在的变量,包括环境变量,我这里以grep筛选出来自定义变量(通常情况下没有办法选出所有自定义变量)

r123@localhost:~$ set | grep first_var
first_var=123456789

取消变量

r123@localhost:~$ unset first_var
r123@localhost:~$ echo $first_var

交互变量

#! /bin/bash

read -p "Input a ipaddress: " ip_address

ping -c 1 ${ip_address} &> /dev/null && echo "${ip_address} Up" || echo "${ip_address} Down"

echo success

三种变量引用

  • ""表示对内部内容进行弱引用,只对空格等字符进行转义,$等不受影响
  • ''表示对内部内容进行强引用,对$等也进行转义
  • ``表示更高的执行优先级
r123@localhost:~$ first_var=123
r123@localhost:~$ echo "$first_var"456
123456
r123@localhost:~$ first_var=123
r123@localhost:~$ echo '$first_var'456
$first_var456
r123@localhost:~$ echo `ls`456
MyMainClass.java content.txt456

变量运算

  • 整数运算
r123@localhost:~$ expr 1 + 1
2
r123@localhost:~$ var_1=123
r123@localhost:~$ var_2=123
r123@localhost:~$ expr $var_1 + $var_2
246

使用expr时,作为运算两个值或变量必须与运算符有空格隔开,还有以下三种方式进行运算

r123@localhost:~$ echo $(($var_1 + $var_2))
246
r123@localhost:~$ echo $((2 ** 2))
4
r123@localhost:~$ echo $[1+2]
3
r123@localhost:~$ let sum=$var_1+$var_2
r123@localhost:~$ echo $sum
246
r123@localhost:~$ let sum++; echo $sum
247
  • 浮点运算

一般浮点运算需要借助bc计算器程序

r123@localhost:~$ sudo apt install bc
r123@localhost:~$ echo "2^4" | bc
16
r123@localhost:~$ echo "scale=3; 2/4" | bc
.500
r123@localhost:~$ echo "scale=3; 5/4" | bc
1.250
r123@localhost:~$ echo "scale=2; 5/4" | bc
1.25

变量类型

环境变量

环境变量是操作系统中的一种配置参数,用于存储系统和应用程序的配置信息。它们是在操作系统运行时由操作系统或用户设置的键值对。这些键值对包含了一些重要的信息,例如系统路径、临时文件夹位置、语言设置等。在计算机程序中,环境变量通常用于指定应用程序的运行时行为,例如定义特定的路径、设置默认值或启用某些功能。程序可以在运行时读取这些环境变量的值,以便适应不同的运行环境或用户需求

通常我们使用export设置临时环境变量用来达到跨shell使用目的,即在当前shell中开启一个子shell后,可以在子shell中使用该变量,我们可以使用pstree来展示shell的层级关系,使用exit来退出当前shell

r123@localhost:~$ export Base_var=233
r123@localhost:~$ ps | grep bash
   40 pts/0    00:00:00 bash
r123@localhost:~$ bash
r123@localhost:~$ bash
r123@localhost:~$ bash
r123@localhost:~$ ps | grep bash
   40 pts/0    00:00:00 bash
   60 pts/0    00:00:00 bash
   67 pts/0    00:00:00 bash
   73 pts/0    00:00:00 bash
r123@localhost:~$ pstree
init─┬─init───init───bash───bash───bash───bash───pstree
     └─{init}
r123@localhost:~$ exit
exit
r123@localhost:~$ pstree
init─┬─init───init───bash───bash───bash───pstree
     └─{init}
r123@localhost:~$ echo $Base_var
233

如果想要设置的变量永久可用,可以添加到环境变量文件,以下是常见表格:

文件 加载时机 说明
/etc/environment 系统启动时 全局环境变量,对所有用户生效
/etc/profile 用户登录时 全局配置文件,对所有用户生效
/etc/bash.bashrc 用户登录时(bash shell) 全局bash配置文件,对所有用户生效
~/.bashrc 用户登录时(bash shell) 用户级别的bash配置文件,只对当前用户生效
~/.bash_profile 用户登录时(bash shell) 用户级别的bash配置文件,仅在用户登录时执行一次
~/.profile 用户登录时 用户级别的配置文件,通常由sh、bash、ksh等解释执行
~/.zshrc 用户登录时(zsh shell) 用户级别的zsh配置文件,只对当前用户生效
/etc/profile.d/ 用户登录时(bash shell) 目录包含由管理员提供的额外配置文件,以扩展/etc/profile
~/.config/environment.d/ 用户登录时 目录包含用户特定的环境变量配置文件,以扩展~/.profile

查看当前shell加载的的环境变量内容:

r123@localhost:~$ env
SHELL=/bin/bash
WSL_DISTRO_NAME=Ubuntu
...

修改环境变量,这里以当前用户环境变量配置为例:

r123@localhost:~$ vim .profile
...
fi
export myself_var=2333
...   
:wq
r123@localhost:~$ source .profile
r123@localhost:~$ echo $myself_var
2333

预定义变量

预定义变量是在Shell脚本中由Shell环境提前定义好的一些特殊变量,用于存储系统信息、脚本运行时的状态等。这些变量在脚本执行期间自动设置,可以用于获取有关执行环境的信息或控制脚本的行为(其中$1$9也称为位置变量):

变量 含义 示例
$0 脚本或命令本身的名称 如果脚本名为 myscript.sh,则 $0myscript.sh
$1, $2, … 传递给脚本或命令的位置参数,9之后的需要特殊定义 $1 表示第一个参数,$2 表示第二个参数,以此类推
$# 传递给脚本或命令的位置参数的总数,或变量的长度${#变量} 如果有三个参数,$# 是 3
$* 所有位置参数的单个字符串 如果有参数为 arg1arg2$*arg1 arg2
$@ 所有位置参数的列表,每个参数作为一个单独的词 如果有参数为 arg1arg2$@arg1arg2
$? 上一个命令的退出状态(返回值),0是成功,非0即为失败 echo $? 可以用于获取上一个命令的退出状态
$$ 当前Shell进程的进程ID echo $$ 显示当前Shell的进程ID
$! 后台运行的上一个命令的进程ID 在后台运行的命令结束后,$! 包含其进程ID
$USER 当前用户的用户名 echo $USER 显示当前登录用户的用户名
$HOME 当前用户的主目录路径 echo $HOME 显示当前用户的主目录路径
$SHELL 当前用户使用的Shell echo $SHELL 显示当前用户使用的Shell
$PATH Shell查找可执行文件的路径列表 echo $PATH 显示Shell查找可执行文件的路径列表

在书写脚本时,我们可以做出以下的效果

ping -c 1 $1 &> /dev/null && echo "${1} is Up" || echo "${1} is Down"
echo success
r123@localhost:~$ vim ping.sh
r123@localhost:~$ bash ping.sh 192.168.179.11
192.168.179.11 is Down
success

条件控制

注意:条件测试不支持浮点值

数值比较

操作符 描述 用法
-eq 等于(equal to) [ "$a" -eq "$b" ]
-ne 不等于(not equal to) [ "$a" -ne "$b" ]
-lt 小于(less than) [ "$a" -lt "$b" ]
-le 小于等于(less than or equal to) [ "$a" -le "$b" ]
-gt 大于(greater than) [ "$a" -gt "$b" ]
-ge 大于等于(greater than or equal to) [ "$a" -ge "$b" ]

如果想要直接使用上述比较,需要通过 $?来获取运算结果:

r123@localhost:~$ [ 20 -gt 10 ]; echo $?
0
r123@localhost:~$ [ 20 -gt 30 ]; echo $?
1
r123@localhost:~$ [ 20-gt30 ]; echo $?
0

需要注意的是,这里的[]运算符需要与运算内容有空格,否则运算将无法识别

文件验证

指令 描述 用法
-e 文件路径 检查文件或目录是否存在 [ -e "$文件路径" ]
-f 文件路径 检查文件是否为普通文件 [ -f "$文件路径" ]
-d 文件路径 检查文件是否为目录 [ -d "$文件路径" ]
-s 文件路径 检查文件是否存在且大小不为零 [ -s "$文件路径" ]
-r 文件路径 检查文件是否可读 [ -r "$文件路径" ]
-w 文件路径 检查文件是否可写 [ -w "$文件路径" ]
-x 文件路径 检查文件是否可执行 [ -x "$文件路径" ]
-L 文件路径 检查文件是否为符号链接 [ -L "$文件路径" ]
-b 文件路径 检查文件是否为块设备文件 [ -b "$文件路径" ]
-g 文件路径 检查文件是否具有设置了 SGID 位 [ -g "$文件路径" ]

文件类型表格:

文件类型 符号 说明
普通文件 - 包含文本、二进制数据等,没有特殊属性。
目录 d 包含其他文件和目录的容器。
符号链接 l 指向另一个文件或目录的链接。
块设备文件 b 提供对设备的带缓冲的访问,如硬盘分区。
字符设备文件 c 提供对设备的不带缓冲的访问,如串口。
套接字文件 s 用于进程间通信的特殊文件。
管道文件 p 用于进程间通信的命名管道。

使用示例:

r123@localhost:~$ ll
total 44
drwxr-x--- 2 r123 r123 4096 Jan 20 00:13 ./
drwxr-xr-x 3 root root 4096 Jan 16 01:32 ../
-rw------- 1 r123 r123 3116 Jan 20 10:44 .bash_history
-rw-r--r-- 1 r123 r123  220 Jan 16 01:32 .bash_logout
-rw-r--r-- 1 r123 r123 3771 Jan 16 01:32 .bashrc
-rw------- 1 r123 r123   20 Jan 20 00:13 .lesshst
-rw-r--r-- 1 r123 r123    0 Jan 20 10:43 .motd_shown
-rw-r--r-- 1 r123 r123  807 Jan 19 15:34 .profile
-rw-r--r-- 1 r123 r123    0 Jan 19 14:47 .sudo_as_admin_successful
-rw------- 1 r123 r123 1444 Jan 19 15:44 .viminfo
-rw-r--r-- 1 r123 r123  127 Jan 17 22:52 MyMainClass.java
-rw-r--r-- 1 r123 r123  152 Jan 17 20:37 content.txt
-rw-r--r-- 1 r123 r123   83 Jan 19 15:44 ping.sh
r123@localhost:~$ [ -f MyMainClass.java ]; echo $?
0
r123@localhost:~$ [ -e MyMainClass.java ]; echo $?
0
r123@localhost:~$ [ -x MyMainClass.java ]; echo $?
1
r123@localhost:~$ [ -g MyMainClass.java ]; echo $?
1
r123@localhost:~$ sudo chmod g+s MyMainClass.java
r123@localhost:~$ [ -g MyMainClass.java ]; echo $?
0

字符串比较

  • 基础用法
r123@localhost:~$ [ "aaa" = "aaa" ]; echo $?
0
  • -z判断字符串长度是0
r123@localhost:~$ [ -z "233"  ]; echo $?
1
r123@localhost:~$ [ -z ""  ]; echo $?
0
  • 判断字符串长度不为0,未定义的变量也为0
r123@localhost:~$ [ -n "233"  ]; echo $?
0
r123@localhost:~$ [ -n ""  ]; echo $?
1

注意:当比较不存在变量时会出现以下情况

r123@localhost:~$ first_var=233
r123@localhost:~$ unset first_var
r123@localhost:~$ echo $first_var

r123@localhost:~$ [ -z $first_var ]; echo $?
0
r123@localhost:~$ [ -n $first_var ]; echo $?
0
r123@localhost:~$ echo $first_var

多条件测试

  • and语法的三种形式
r123@localhost:~$ [ 22 -gt 23 -a 23 -gt 22 ]; echo $?
1
r123@localhost:~$ [[ 22 -gt 23 && 23 -gt 22 ]]; echo $?
1
r123@localhost:~$ [ 22 -gt 23 ] && [ 23 -gt 22 ]; echo $?
1
  • or语法的三种形式
r123@localhost:~$ [ 22 -gt 23 -o 23 -gt 22 ]; echo $?
0
r123@localhost:~$ [[ 22 -gt 23 || 23 -gt 22 ]]; echo $?
0
r123@localhost:~$ [ 22 -gt 23 ] || [ 23 -gt 22 ]; echo $?
0

模式匹配

利用linux的通配符来进行匹配条件

r123@localhost:~$ [[ 2 = [0-9] ]]; echo $?
0
r123@localhost:~$ [[ 20 = [0-9] ]]; echo $?
1

正则匹配

使用~表示进行正则匹配

r123@localhost:~$ [[ 20 =~ [0-9] ]]; echo $?
0
r123@localhost:~$ [[ a =~ [0-9] ]]; echo $?
1
r123@localhost:~$ [[ 1 =~ ^[0-9]$ ]]; echo $?
0
r123@localhost:~$ [[ 20 =~ ^[0-9]$ ]]; echo $?
1
r123@localhost:~$ [[ 2 =~ ^[0-9]$ ]]; echo $?
0

流程控制if语法

  • 单分支结构,当条件控制语句成立(返回值为0),输出Hello World
#!/bin/bash

if [ 2 -gt 1 ]; then
        echo "Hello World";
fi
r123@localhost:~$ cat if_test.sh

#!/bin/bash
read -p "Please enter a username: " username
id $username &> /dev/null
if [ $? -eq 0 ]; then
        echo "The username is exist"
fi

r123@localhost:~$ bash if_test.sh
Please enter a username: r123
The username is exist
  • 双分支结构
r123@localhost:~$ cat if_test.sh

#!/bin/bash
read -p "Please enter a username: " username
id $username &> /dev/null
if [ $? -eq 0 ]
then
        echo "The username is exist"

else
        echo "The username is not exist"
fi

r123@localhost:~$ bash if_test.sh
Please enter a username: r123
The username is exist
r123@localhost:~$ bash if_test.sh
Please enter a username: aaa
The username is not exist

这里使用了$?来避免了直接将命令作为条件传入if语句,也可以直接将命令作为条件

  • 多分支结构
#!/bin/bash
read -p "Please enter a time of only hour: " user_input_hour

if [ $user_input_hour -gt 24 -o $user_input_hour -lt 0 ];
then
    echo "Please enter a correct time"

elif [ $user_input_hour -le 12 ]
then 
    echo "It's ${user_input_hour} o'clock in the morning"

elif [ $user_input_hour -gt 12 ]
then
    echo "It's ${user_input_hour} o'clock in the afternoon"

else
    echo "Failed test"

fi

使用bash -vx 脚本名可以进行调试脚本

r123@localhost:~$ bash -vx elif_test.sh
#!/bin/bash
read -p "Please enter a time of only hour: " user_input_hour
+ read -p 'Please enter a time of only hour: ' user_input_hour
Please enter a time of only hour: 12

if [ $user_input_hour -gt 24 -o $user_input_hour -lt 0 ];
then
    echo "Please enter a correct time"
...
elif [ $user_input_hour -gt 12 ]
then
    echo "It's ${user_input_hour} o'clock in the afternoon"

else
    echo "Failed test"

fi
+ '[' 12 -gt 24 -o 12 -lt 0 ']'
+ '[' 12 -le 12 ']'
+ echo 'It'\''s 12 o'\''clock in the morning'
It's 12 o'clock in the morning

在每一句要执行的语句处,将依次输出:原语句、进行操作(以+开头)、执行结果

模式匹配case语法

read -p "Please enter a number from 0 to 9 or a letter: "  user_input_value

case $user_input_value in
    [0-9])
        echo "This is a number which in 1-9"
    ;;
    [a-zA-Z])
        echo "This is a letter"
    ;;
    *)
        echo "no"
    ;;
esac

匹配模式为模式匹配,并不能直接使用正则表达式,在每个模式匹配完成后需要使用两个分号,借助以上基础知识,我们可以写一个略微复杂的脚本

#!/bin/bash
web1=192.168.179.2
web2=192.168.179.3
web3=192.168.179.144
web4=192.168.179.145
web5=192.168.179.200

cat <<EOF
    1.Web Server 1 ${web1}
    2.Web Server 2 ${web2}
    3.Web Server 3 ${web3}
    4.Web Server 4 ${web4}
    5.Web Server 5 ${web5}
EOF

read -p "Please select a Web Server serial number: " select_res

case $select_res in
1)
    select_res=$web1
    ;;
2)
    select_res=$web2
    ;;
3)
    select_res=$web3
    ;;
4)
    select_res=$web4
    ;;
5)
    select_res=$web5
    ;;
esac

echo "The selected host to connect to is Web Server: "$select_res

ping -c 1 $select_res &> /dev/null && echo "${select_res} Up" || echo "${select_res} Down"

echo "Execution is completed"

你可能感兴趣的:(linux,运维,自动化)