上一章:
在编写shell脚本时,直接在shell终端中,写脚本,感觉有点不是很方便,没有提示。
在其他工具中,写shell脚本时,会有提示。
目录
8.3.1 command >/dev/null 2>&1 &
8.3.2 command >out.file 2>&1 &
9.4.3 -s 输入的内容不显示在当前屏幕(输入密码场景)
七、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