Shell编程(二)

上一章:

Shell编程_做测试的喵酱的博客-CSDN博客

在编写shell脚本时,直接在shell终端中,写脚本,感觉有点不是很方便,没有提示。

在其他工具中,写shell脚本时,会有提示。 

目录

七、ping

八、2>&1

8.1  1和2在Linux中的含义

8.2  2>&1的含义

8.3 举例

8.3.1  command >/dev/null 2>&1 &

8.3.2 command >out.file 2>&1 & 

九、函数

9.1 定义函数的格式

9.2  ping host 小案例

 9.3 参数

9.4 read 提示并获取用户输入

9.4.1 -p 提示用户输入信息

9.4.2 -n 读取指定字符

9.4.3 -s 输入的内容不显示在当前屏幕(输入密码场景)

10、流程控制

10.1 变量的几种写法

10.2 条件表达式

10.3 常用判断条件:

10.4 if 

10.1.1 举例:

10.2 for 循环

10.3  while循环

10.3.1 算数表达式  $((算数表达式)) 

10.3.2 while 循环

10.4 until 循环

10.5 case... esac


七、ping

查看当前服务,是否能ping通baidu

ping www.baidu.com

[root@ecs-39233 dev]# ping www.baidu.com
PING www.a.shifen.com (110.242.68.4) 56(84) bytes of data.
64 bytes from 110.242.68.4 (110.242.68.4): icmp_seq=1 ttl=49 time=10.2 ms
64 bytes from 110.242.68.4 (110.242.68.4): icmp_seq=2 ttl=49 time=10.2 ms
64 bytes from 110.242.68.4 (110.242.68.4): icmp_seq=3 ttl=49 time=10.2 ms
64 bytes from 110.242.68.4 (110.242.68.4): icmp_seq=4 ttl=49 time=10.2 ms
64 bytes from 110.242.68.4 (110.242.68.4): icmp_seq=5 ttl=49 time=10.2 ms
^C
--- www.a.shifen.com ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4005ms
rtt min/avg/max/mdev = 10.214/10.225/10.236/0.111 ms

在当前屏幕,会持续输出ping的内容。

我想实现,ping 只打印一行输出内容。

查看ping 的帮助文档。

ping --help

查看ping的详细介绍文档

man ping

 ping -c 可以实现打印行数的控制。 -c1打印一行, -c2打印两行

ping -c1 www.baidu.com
[root@ecs-39233 dev]# ping -c1 www.baidu.com
PING www.a.shifen.com (110.242.68.4) 56(84) bytes of data.
64 bytes from 110.242.68.4 (110.242.68.4): icmp_seq=1 ttl=49 time=10.2 ms

--- www.a.shifen.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 10.232/10.232/10.232/0.000 ms

八、2>&1

linux中的2>&1是什么_2&>1_康大壮的博客-CSDN博客

Linux 中 2>&1 详解_2>&1_迎风悟极道的博客-CSDN博客

8.1  1和2在Linux中的含义

在Linux系统中0 1 2是一个文件描述符:


标准的输入,输出和错误输出分别表示为STDIN,STDOUT,STDERR,也可以用0,1,2来表示。

名称 代码   Linux 下文件描述符(Debian 为例)
标准输入(stdin)  0  /dev/stdin -> /proc/self/fd/0 -> /dev/pts/0
标准输出(stdout)  1  /dev/stdout -> /proc/self/fd/1 -> /dev/pts/0
标准错误输出(stderr) 2  /dev/stderr -> /proc/self/fd/2 -> /dev/pts/0

 
其中0表示键盘输入 1表示屏幕输出 2表示错误输出。

8.2  2>&1的含义

2>&1的含义:将标准错误输出重定向标准输出

注意:符号>&是一个整体,不可分开,分开后就不是上述含义了。

8.3 举例

8.3.1  command >/dev/null 2>&1 &

command  我们写的指令

> 重定向

/dev/null  表示空设备文件,相当于垃圾桶

2 标准错误输出

1 标准输出

2>&1的含义:将标准错误输出重定向标准输出。注意:2>&1,中间不能有空格。

注意:符号>&是一个整体,不可分开,分开后就不是上述含义了。

command>/dev/null ,它默认等于command 1>/dev/null ,即将标准输出结果重定向到/dev/null

2>&1,  将标准错误输出重定向标准输出 。标准输出1,已经被重定向到了/dev/null,错误输出重定向到标准输出,则错误输出也被重定向到了/dev/null

最后一个&, 是让该命令在后台执行。

8.3.2 command >out.file 2>&1 & 

command >out.file        是将command的输出重定向到out.file文件,输出内容不打印到屏幕上,而是输出到out.file文件中。
2>&1        是将标准出错重定向到标准输出,因为标准输出已经重定向到了out.file文件,所以标准出错也输出到out.file文件中。
最后一个&, 是让该命令在后台执行。  


 

九、函数

 shell脚本,是一个面向过程的编程语言,没有类和对象的概念。用的最多的就是函数。

9.1 定义函数的格式

定义函数,有2种方式。

定义函数,方式一

函数名()
{
    命令1
    命令2
    ....
}

命令1,前的空格一般空四个 。

定义函数,方式二

使用function 关键字

function 函数名
{
    命令1
    命令2
    ...
}

命令1,前的空格一般空四个 。使用function 定义函数时,函数名后没有括号。

举例:

创建 study_shell.sh 

#!/bin/bash
# author: miao
# date: 2023

# 方法一,打印当前登录用户名称和时间
print_user()
{
    echo -e "Hello ${USER},date: $(date)"
}


# 方法二,打印当前路径

function print_pwd
{
    echo "$(pwd)"
}


# 调用方法一
print_user

# 调用方法二

print_pwd

注意:

调用变量的格式,${USER}

调用方法的格式, $(date)

执行 study_shell.sh 

[root@ecs-39233 chenshuai]# sh study_shell.sh 
Hello root,date: Tue Apr 18 07:31:08 CST 2023
/chenshuai

9.2  ping host 小案例

实现一个ping 功能的函数 。以www.baidu.com 为例

如何判断ping 通。我们可以通过echo $? 查看状态。

ping 一个不存在的地址

[root@ecs-39233 ~]# ping -c1 www.baidusssss.com; echo $?
ping: www.baidusssss.com: Name or service not known
2

返回非0

ping 百度,返回0

[root@ecs-39233 ~]# ping -c1 www.xxxx.com; echo $?
PING www.xxxx.com (54.153.216.130) 56(84) bytes of data.
64 bytes from ec2-54-153-216-130.ap-southeast-2.compute.amazonaws.com (54.153.216.130): icmp_seq=1 ttl=35 time=165 ms

--- www.xxxx.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 165.493/165.493/165.493/0.000 ms
0

ping -c1 www.baidu.com > /dev/null 2>&1

ping -c1 打印一行输出

> /dev/null 将标准输出,重定向到虚拟文件

2>&1 2标准错误输出,等同于>& 标准输出1。(都会重定向到/dev/null)中 

编写脚本check_host.sh

vim check_host.sh
#!/bin/bash
# author: miao
#description: check host,检查主机是否在线

function check_host
{
    ping -c1 www.baidu.com &> /dev/null
    test $? -eq 0 && echo -e "服务【www.baidu.com】正常启动" || echo -e "服务【www.baidu.com】离线状态"
}

# 调用函数
check_host

注意,脚本中 &> /dev/null 中的 &> 表示将所有的输出(标准输出和标准错误输出)全部重定向

运行脚本sh check_host.sh

[root@ecs-39233 ~]# sh check_host.sh 
服务【www.baidu.com】正常启动

 9.3 参数

9.2 中,ping host 案例,host是写死的。现在用传参变量代替里面的host。

函数获取参数的形式,与命令行获取参数的形式是一样的。都是通过$1 获取。

在函数的内部,使用$1 就可以获取第一个参数。$2 就可以获取第二个参数。

对 check_host.sh 进行改造。

复制一份

cp check_host.sh new_check_host.sh

修改 new_check_host.sh

vim new_check_host.sh

用变量替换里面的host

#!/bin/bash
# author: miao
#description: check host,检查主机是否在线

function check_host
{
    server_name="$1"
    host="$2"
    ping -c1 "${host}" &> /dev/null
    test $? -eq 0 && echo -e "服务【${server_name}】正常启动" || echo -e "服务【${server_name}】离线状态"
}

# 调用函数
check_host $1 $2

直接运行 new_check_host.sh  脚本

[root@ecs-39233 ~]# sh new_check_host.sh 
服务【】离线状态

使用参数,百度 www.baidu.com

[root@ecs-39233 ~]# sh new_check_host.sh 百度 www.baidu.com
服务【百度】正常启动

讲解脚本中的参数传递。

函数check_host 中,使用了两个变量 $1 $2(函数内部 参数)

$1 表示调用函数check_host 函数时第一个参数。

在调用check_host 的代码中。参数$1 $2 ,获取的是调用new_check_host.sh  脚本时,用户在命令行中输入的参数。

9.4 read 提示并获取用户输入

在运行脚本时,提示用户输入参数。

python 提示用户输入,获取收入参数用的input 函数。

shell编程中,使用的是read函数。

9.4.1 -p 提示用户输入信息

实现功能: 

在终端页面,提示用户输入内容,并接收用户输入的内容。

使用read -p 可以提示用户输入。

复制 new_check_host.sh  脚本

cp new_check_host.sh study_read_p_check_host.sh

修改 study_read_p_check_host.sh 脚本

#!/bin/bash
# author: miao
#description: check host,检查主机是否在线

read -p "请输入主机名称"
read -p "请输入主机ip"

function check_host
{
    server_name="$1"
    host="$2"
    ping -c1 "${host}" &> /dev/null
    test $? -eq 0 && echo -e "服务【${server_name}】正常启动" || echo -e "服务【${server_name}】离线状态"
}
check_host

运行脚本

[root@ecs-39233 ~]# sh study_read_p_check_host.sh 
请输入主机名称111
请输入主机ip3333
服务【】离线状态

这样就实现了提示用户输入的功能了。如何获取用户输入的变量呢?

使用变量获取用户输入:

1、内置变量

2、自定义变量

1、内置变量,$REPLY 

使用read函数时,使用内置变量 $REPLY 接收参数。 当用户只输入一个变量时,可以用内置变量 $REPLY 来接收。 当有多个变量输入时。$REPLY 变量的值会被覆盖,显示最后输入的值。

举例:

vim test_read_reply.sh
#!/bin/bash

read -p "请输入你的姓名"
echo
echo "你的姓名是 ${REPLY}"

其中空的echo 是为了在屏幕输入时,换行显示用的。

[root@ecs-39233 ~]# sh test_read_reply.sh 
请输入你的姓名喵先生

你的姓名是 喵先生

当有多个输入变量时,$REPLY 会被覆盖

vim test_read_reply_1.sh
#!/bin/bash

read -p "请输入你的姓名"
read -p "请输入你的年龄"
echo
echo "变量REPLY的值是 ${REPLY}"

运行脚本

[root@ecs-39233 ~]# sh test_read_reply_1.sh 
请输入你的姓名张三
请输入你的年龄18

变量REPLY的值是 18

2、自定义变量

当需要获取输入的多个变量时,使用自定义变量

read -p “提示输入内容” 自定义变量名称

编辑study_read_p_check_host.sh 脚本

vim study_read_p_check_host.sh
#!/bin/bash
# author: miao
#description: check host,检查主机是否在线

read -p "请输入主机名称" server_name
read -p "请输入主机ip" host

function check_host
{
    server_name="${server_name}"
    host="${host}"
    ping -c1 "${host}" &> /dev/null
    test $? -eq 0 && echo -e "服务【${server_name}】正常启动" || echo -e "服务【${server_name}】离线状态"
}
check_host

运行脚本

sh study_read_p_check_host.sh

[root@ecs-39233 ~]# sh study_read_p_check_host.sh
请输入主机名称百度
请输入主机ipwww.baidu.com
服务【百度】正常启动

9.4.2 -n 读取指定字符

实现功能:

linux 上,安装程序的过程中,经常提示我们输入Y 或者输入N 。只输入一个字符。

脚本在读取用户输入的时候,只读取第一个字符。

功能的实现: read -n

只读取用户输入的第一个字符 read -n1

创建脚本

vim test_read_n.sh
#!/bin/bash

read -n1 -p "是否继续安装,输入Y/N"
echo
echo "你输入的是 $REPLY"

运行脚本

[root@ecs-39233 ~]# sh test_read_n.sh 
是否继续安装,输入Y/Ny
你输入的是 y

当我输入一个字符时,程序就自动执行并断开了。不会让我再次输入第二个字符。 

9.4.3 -s 输入的内容不显示在当前屏幕(输入密码场景)

实现功能:

在终端输入密码时,密码不显示在当前屏幕。

功能的实现:read -s

创建脚本, vim read_s.sh

#!/bin/bash
# description: read -s test
read -s -p "输入登录密码:"
echo
echo
echo "输入密码成功"

运行

[root@ecs-39233 ~]# sh read_s.sh
输入登录密码:

输入密码成功

在输入密码时,没有回显输入内容。

10、流程控制

10.1 变量的几种写法

$name

"$name"

"${name}"

10.2 条件表达式

条件表达式,三种方式。

方式一

test 条件表达式

方式二 方括号

[ 条件表达式 ]

注意,方括号的首尾都要有一个空格,不然报错。 

方式三

 [[ 条件表达式 ]]

10.3 常用判断条件:

字符串比较(=)

两个整数的比较

-lt(小于)
-le(小于等于)
-eq(等于)
-gt(大于)
-ge(大于等于)
-ne(不等于)


按照文件权限进行判断

-r (有读的权限)
-w (有写的权限)
-x(有执行的权限)


按照文件类型进行判断

-f(文件存在并且是一个常规文件)
-e(文件存在)
-d(文件存在并是一个目录)
 

10.4 if 

方式一

if [ 条件1 ]
then
	指令1
elif [ 条件2 ]
then
	指令2
else
	指令3
fi

方式二

if [ 条件1 ]; then
	指令1
elif [ 条件2 ]; then
	指令2
else
	指令3
fi

注意运行条件 的,[], 前后要保留一个空格。 [] 与我们前面的test是等价的。

开头是if, 结尾是反着的if,fi

10.1.1 举例:

1、判断学生成绩:

大于使用 -gt,小于使用 -lt

条件表达式,两个方括号[[ ]]

#!/bin/bash
# author: miao
# desc: if流程语句练习

read -p "请输入学生的姓名" name
read -p "请输入成绩" score

if [[ "$score" -gt 80 ]]; then
	#statements
	echo "${name} 的成绩很优秀"
elif [[ "${score}" -gt 60 ]]; then
	#statements
	echo "${name} 的成绩:及格"
else
	echo "${name} 的成绩不及格"
fi

条件表达式,1个方括号 []

read -p "请输入学生的姓名" name
read -p "请输入成绩" score

if [ "$score" -gt 80 ]; then
	#statements
	echo "${name} 的成绩很优秀"
elif [ "${score}" -gt 60 ]; then
	#statements
	echo "${name} 的成绩:及格"
else
	echo "${name} 的成绩不及格"
fi

条件表达式,使用test

read -p "请输入学生的姓名" name
read -p "请输入成绩" score

if test "$score" -gt 80; then
	#statements
	echo "${name} 的成绩很优秀"
elif test "${score}" -gt 60; then
	#statements
	echo "${name} 的成绩:及格"
else
	echo "${name} 的成绩不及格"
fi

[root@ecs-39233 ~]# sh if.sh 
请输入学生的姓名张三
请输入成绩99
张三 的成绩很优秀
[root@ecs-39233 ~]# sh if.sh 
请输入学生的姓名李四
请输入成绩50
李四 的成绩不及格

判断mysql是否启动成功

if netstat -tlunp | grep ":3306" &>/dev/null; then
	echo "mysql已启动"
else
	echo "mysql未启动"
fi

10.2 for 循环

基本语法1:

for循环一般格式为:

for 变量 in 值1 值2 值3...
do
    程序1
    程序2
    程序3
done

 写成一行:

for var in item1 item2 ... itemN; do command1; command2… done;

举例,顺序输出当前列表中的数字:

#!/bin/bash

for loop in 1 2 3 4 5
do
    echo "The value is: $loop"
done

输出结果:

The value is: 1
The value is: 2
The value is: 3
The value is: 4
The value is: 5

顺序输出字符串中的字符:

#!/bin/bash

for str in This is a string
do
    echo $str
done

输出结果:

This
is
a
string

基本语法2:

for((初始值;循环控制条件;变量变化))
do
程序
done

10.3  while循环

10.3.1 算数表达式  $((算数表达式)) 


使用方式:

$((算数表达式))


举例 

[root@ecs-39233 ~]# a=1
[root@ecs-39233 ~]# b=2
[root@ecs-39233 ~]# c=3
[root@ecs-39233 ~]# echo $(($a+$b + $c))
6


注意:

表达式中,$(($a+$b + $c)) 可以有空格,也可以没有空格。


10.3.2 while 循环

while 循环用于不断执行一系列命令,也用于从输入文件中读取数据。其语法格式为:

基本语法:

while [ 条件判断式 ]
do
    程序
done

以下是一个基本的 while 循环。

测试条件是:如果 int 小于等于 5,那么条件返回真。int 从 1 开始,每次循环处理时,int 加 1。运行上述脚本,返回数字 1 到 5,然后终止。

举例:

#!/bin/bash
int=1
while(( $int<=5 ))
do
    echo $int
    let "int++"
done

运行脚本,输出:

1
2
3
4
5

注意:

以上实例使用了 Bash let 命令,它用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量 

10.4 until 循环

until 循环执行一系列命令直至条件为 true 时停止。

until 循环与 while 循环在处理方式上刚好相反。

一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下,until 循环更加有用。

until 语法格式:

until [ 条件表达式 ]
do
    程序1
    程序2
done
 
 

 条件表达式,如果返回值为 false,则继续执行循环体内的语句,否则跳出循环。

以下实例我们使用 until 命令来输出 0 ~ 9 的数字:

-lt 小于

$((算术表达式))

#!/bin/bash
a=0
until [[ ! $a -lt 10 ]]; do
        #statements
        echo "$a"
        a=$(($a + 1))
done

10.5 case... esac

case ... esac 为多选择语句,与java中的 switch ... case 语句类似,是一种多分支选择结构。

每个 case 分支用右圆括号开始,用两个分号 ;; 表示 break,即执行结束,

跳出整个 case ... esac 语句,esac(就是 case 反过来)作为结束标记。

可以用 case 语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。

case ... esac 语法格式如下:

case 值 in
模式1)
    command1
    command2
    ...
    commandN
    ;;
模式2)
    command1
    command2
    ...
    commandN
    ;;
esac

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

取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号 * 捕获该值,再执行后面的命令。

下面的脚本提示输入 1 到 4,与每一种模式进行匹配:

vim test_case.sh

read -p '输入 1 到 4 之间的数字:' num
echo "你输入的数字为: ${num}"
case $num in
    1)  echo '你选择了 1'
    ;;
    2)  echo '你选择了 2'
    ;;
    3)  echo '你选择了 3'
    ;;
    4)  echo '你选择了 4'
    ;;
    *)  echo '你没有输入 1 到 4 之间的数字'
    ;;
esac
[root@ecs-39233 chenshuai]# sh test_case.sh
输入 1 到 4 之间的数字:2
你输入的数字为: 2
你选择了 2

下面的脚本匹配字符串:

#!/bin/sh

site="runoob"

case "$site" in
   "runoob") echo "菜鸟教程"
   ;;
   "google") echo "Google 搜索"
   ;;
   "taobao") echo "淘宝网"
   ;;
esac

猜你喜欢

转载自blog.csdn.net/qq_39208536/article/details/130210992