脚本交互 以及表达式
1. 概述
嗨,我又来继续分享了。今天分享的内容是脚本交互,再开始接下来的分享开始之前,让我们来回顾下上一次(【shell 编程大全】内容格式化以及多样化输出)的内容:
- 内容格式化
- 重定向
- 管道符
- 后台执行
- 信息符号
- 输入格式化
- eof原理
- cat 实践
- tee 实践
- 输出格式化
- echo 解读
- 颜色输出
- 颜色分类
- printf 格式化
2. 登录shell 关联配置文件
文本讲述下 如果你要登录shell,会执行哪些文件以及每个文件都是干什么的
# 系统级别生效配置文件
# 系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行
/etc/profile
# 被/etc/profile文件调用,执行当前目录下所有的文件中关于shell的设置
/etc/profile.d/*.sh
# 为每一个运行bash shell的用户执行此文件.当bash shell被打开时,该文件被读取
/etc/bashrc
# 用户级别生效配置文件
# 设定用户专用的shell信息,当用户登录时,该文件仅仅执行一次
~/.bash_profile
# 该文件包含用户专用的bash信息,当登录时以及每次打开新的shell时,该文件被读取
~/.bashrc
# 用户退出生效配置文件
# 当每次退出系统(退出bash shell)时,执行该文件.
~/.bash_logout
# 用户登录时自动读取其中的内容并加载到内存hiatory记录中logout时将内存中的history记录写入该文件中
~/.bash_history
下面是打印结果
- 先执行系统级别的配置文件
/etc/profile
. 在该文件中执行/profile.d
下的所有shell。 - 执行文件夹
/profile.d
下的所有的shell - 执行文件配置
/etc/bashrc
- 开始执行用户级别的文件,
~/.bash_profile
. - 最后执行文件
~/.bashrc
3. 什么是子shell
对于一些临时性的场景,我们在临时性的环境中,做一些操作,但是不希望对外部的环境造成影响,这个时候我们就涉及到了一些临时shell环境的实践。关于临时shell环境的创建,我们可以借助于()方法来实现。
一般我们要实现临时环境有以下两种方式:
- 启动子shell。(命令列表),在子shell中执行命令列表,退出子shell后,不影响后续环境操作。
- 不启动子shell。{命令列表}, 在当前shell中运行命令列表,会影响当前shell环境的后续操作。
案例演示
[root@localhost ~]# echo ${name}
[root@localhost ~]# (export name=lihh; echo ${name};)
lihh
[root@localhost ~]# echo ${name}
[root@localhost ~]#
上述实例是启动子shell的情况下,在符号()
中定义的变量,不会影响到外部
[root@localhost ~]# echo ${name}
[root@localhost ~]# { export name=lihh; echo ${name}; }
lihh
[root@localhost ~]# echo ${name}
lihh
[root@localhost ~]#
上述示例是不启用子shell的情况,在符号{}
内部定义的变量,会影响外面的
4. umask 修改默认权限
认识umask
umask指的是文件权限默认的掩码,默认的值是022
- 默认创建的目录是777-022=755
默认创建的文件是666-022-644
示例
[root@localhost day06]# umask
0022
[root@localhost day06]# touch file1
[root@localhost day06]#
[root@localhost day06]# mkdir folder1
[root@localhost day06]# ll
total 0
-rw-r--r--. 1 root root 0 Feb 13 15:20 file1
drwxr-xr-x. 2 root root 6 Feb 13 15:20 folder1
[root@localhost day06]#
通过上述示例,生成的文件默认权限就是644
,生成文件夹默认权限就是755
让我们来修改下 umask 试试
[root@localhost day06]# umask 666
[root@localhost day06]# umask
0666
[root@localhost day06]# touch file2
[root@localhost day06]# mkdir folder2
[root@localhost day06]# ll
total 0
----------. 1 root root 0 Feb 13 15:23 file2
d--x--x--x. 2 root root 6 Feb 13 15:23 folder2
5. read基础
read命令是用于从终端或者文件中读取输入的内建命令,read命令读取整行输入,每行末尾的换行符不被读入。在read命令后面,如果没有指定变量名,读取的数据将被自动赋值给特定的变量REPLY
read 命令格式如下:
read 从标准输入读取一行并赋值给特定变量REPLY。
read answer 从标准输入读取输入并赋值给变量answer。
read first last 从标准输入读取内容,将第一个单词放到first中,其他内容放在last中。
read -s passwd 从标准输入读取内容,写入passwd,不输入效果
read -n n name 从标准输入读取内容,截取n个字符,写入name,超过n个字符,直接退出
read -p "prompt" 打印提示,等待输入,并将输入存储在REPLY中。
read -r line 允许输入包含反斜杠。
read -t second 指定超时时间,默认是秒,整数
read -d sper 指定输入信息的截止符号
实战
[root@localhost day06]# cat tshell001.sh
#!/bin/bash
# 写交互命令的子shell
echo "======================= 请输入登录信息 ========================="
read -p "请输入账号:" account
read -s -t 20 -p "请输入密码:" password
echo ""
echo "======================= 输入结束 ========================="
echo "您输入的账号是:${account}"
echo "您输入的密码是:${password}"
[root@localhost day06]# /bin/bash ./tshell001.sh
======================= 请输入登录信息 =========================
请输入账号:lihh
请输入密码:
======================= 输入结束 =========================
您输入的账号是:lihh
您输入的密码是:123456
6. 表达式
6.1 简单计算表达式
6.1.1 $[]
$[]方法,常用于整数计算场景,适合不太复杂的计算,运算结果是小数的也会自动取整。
格式
# 格式1
$[计算表达式]
# 格式2
a=$[变量名a+1]
示例
[root@localhost day06]# echo $[100/2]
50
[root@localhost day06]# echo $[99/2]
49
[root@localhost day06]# num=1
[root@localhost day06]# echo ${num}
1
[root@localhost day06]# num=$[ num+1 ]
[root@localhost day06]# echo ${num}
2
[root@localhost day06]#
6.1.2 let
格式
# 格式
let 变量名a=变量名a+1
示例
[root@localhost day06]# echo ${num}
[root@localhost day06]# num=1
[root@localhost day06]# let num=num+1
[root@localhost day06]# echo ${num}
2
[root@localhost day06]#
6.1.3 (())
此符号的用法跟
let
是保持一致的
[root@localhost day06]# echo ${i}
[root@localhost day06]# i=100
[root@localhost day06]# ((i=i+1))
[root@localhost day06]# echo ${i}
101
[root@localhost day06]#
6.1.4 $(())
$(())的操作,相当于 (()) + echo $变量名 的组合
格式
echo $((变量计算表达式))
注意:
对于 $(())中间的表达式,可以不是一个整体,不受空格的限制
示例
[root@localhost day06]# echo ${i}
[root@localhost day06]# i=100
[root@localhost day06]# echo $((i=i+1))
101
[root@localhost day06]#
6.2 expr 计算
expr即可以做常见的整数运算,还可以做数字比较,字符串计算等操作。
格式
数字场景:
expr 运算表达式
字符串场景:
match:用户获取匹配到字符串的长度
expr match 字符串 匹配内容
substr:截取字符串
expr substr 字符串 起始位置 截取长度
注意:起始位置值>=1
index:查找第一次匹配字符的位置
expr index 字符串 字符
length:计算字符串的长度
expr length 字符串
6.2.1 match
获取用户 匹配到字符串的长度,如果某一个字符,在字符串中出现了很多次,以最后一次为准
[root@localhost day06]# name=gsfsfegdrgdfsfs
[root@localhost day06]# echo ${name}
gsfsfegdrgdfsfs
[root@localhost day06]# expr match $name ".*f"
14
[root@localhost day06]#
6.2.2 substr
用来截取字符串,下标从1开始计算
[root@localhost day06]# echo ${name}
gsfsfegdrgdfsfs
[root@localhost day06]# expr substr $name 1 4
gsfs
[root@localhost day06]#
6.2.3 index
[root@localhost day06]# echo ${name}
gsfsfegdrgdfsfs
[root@localhost day06]# expr index $name f
3
[root@localhost day06]#
6.2.4 length
[root@localhost day06]# echo ${name}
gsfsfegdrgdfsfs
[root@localhost day06]# expr length $name
15
[root@localhost day06]#
6.3 bc计算
bc是一种任意精度的计算语言,提供了语法结构,比如条件判断、循环等,功能是很强大的,还能进行进制转换。
格式
常见参数
-i 强制交互模式;
-l 使用bc的内置库,bc里有一些数学库,对三角计算等非常实用;
-q 进入bc交互模式时不再输出版本等多余的信息。
特殊变量
ibase,obase 用于进制转换,ibase是输入的进制,obase是输出的进制,默认是十进制;
scale 小数保留位数,默认保留0位。
shell中实践
[root@localhost day06]# echo "scale=2; 9-1/7" | bc
8.86
[root@localhost day06]# echo "scale=1; 9-1/7" | bc
8.9
[root@localhost day06]# echo "9-1/7" | bc
9
[root@localhost day06]#
我们可以利用bc的一些API为我们做一些事情。只需要将内容通过管道符传递给bc 即可
6.4 测试表达式
格式
样式1: test 条件表达式
样式2: [ 条件表达式 ]
注意:
以上两种方法的作用完全一样,后者为常用。
但后者需要注意方括号[、]与条件表达式之间至少有一个空格。
test跟 [] 的意思一样
条件成立,状态返回值是0
条件不成立,状态返回值是1
示例
通过上述格式我们得知,测试表达式一般有两种格式,接下来让我们依次试试两种格式
通过test
来对表达式进行检验
[root@localhost day06]# test 1 == 1
[root@localhost day06]# echo $?
0
[root@localhost day06]# test 1 == 2
[root@localhost day06]# echo $?
1
[root@localhost day06]# echo $name
gsfsfegdrgdfsfs
[root@localhost day06]# test -v name
[root@localhost day06]# echo $?
0
[root@localhost day06]# unset name
[root@localhost day06]# test -v name
[root@localhost day06]# echo $?
1
[root@localhost day06]#
通过符号[]
来对表达式进行校验
[root@localhost day06]# [ 1 == 1 ]
[root@localhost day06]# echo $?
0
[root@localhost day06]# [ 1 == 2 ]
[root@localhost day06]# echo $?
1
[root@localhost day06]#
6.5 逻辑表达式
其实逻辑表达式无非是
&&
,||
,!
. 废话不多说,我们来看几个实例
实例 1
下列 条件判断 跟 输出语句 是 && 关系。所以只有第一个满足的时候,才会执行第二个表达式
[root@localhost day06]# [ 1 == 1 ] && echo "1 == 1 满足,我就执行了"
1 == 1 满足,我就执行了
实例 2
下面的命令是由三个语句组成的,很显然第一个条件判断一定是不满足的,所以 && 不可能执行。只能执行 || 语句了
[ 1 == 2 ] && echo "1 == 1 满足,我就执行了" || echo "条件不满足,轮到我执行了"
条件不满足,轮到我执行了
实例 3
虽然第一个表达式不满足条件,但是结果取反了,所以执行了第二个表达式。
[ ! 1 == 2 ] && echo "1 == 2 不满足,但是我去反了,我就执行了"
1 == 2 不满足,但是我去反了,我就执行了
实例 4
判断参数个数,执行不同的逻辑
[root@localhost day06]# cat tshell002.sh
#!/bin/bash
# 判断参数个数
args=$#
[ $args == 1 ] && echo "参数个数为1, 成功执行"
[ $args == 1 ] || echo "参数个数不为1, 失败执行"
实例 5
通过组合使用来判断目录是否存在
[root@localhost day06]# [ -d /etc ] && echo "/etc 目录存在" || echo "/etc 目录不存在"
/etc 目录存在
[root@localhost day06]# [ -d /etc1 ] && echo "/etc1 目录存在" || echo "/etc1 目录不存在"
/etc1 目录不存在
[root@localhost day06]#
案例 6
通过shell 脚本检测服务器 活性
#!/bin/bash
# 表示ip检测
# 接受变量
_ip=$1
_ipN=$#
# ip非空判断
[ -z ${_ip} ] && echo "请输入检测IP" && exit
# 参数个数判断
[ ${_ipN} -ne 1 ] && echo "请保证输入一个脚本参数" && exit
# 执行命令
ping -c1 -w1 ${_ip} > /dev/null 2>&1
# 接受状态
status=$([ $? == 0 ] && echo "正常" || echo "异常")
echo "=============== 输出结果 ===================="
echo "您的IP<${_ip}>, 检测结果是: ${status}"
[root@localhost day06]# /bin/bash ./tshell003.sh 192.168.56.10
=============== 输出结果 ====================
您的IP<192.168.56.10>, 检测结果是: 正常
6.6 字符串表达式
==
判断两个字符串的内容是否一致!=
判断两个字符串的内容是否不一致-z xxx
空值判断,如果字符串的长度为0,返回true-n xxx
非空判断,如果字符串的长度不为0,返回true
6.7 文件表达式
文件属性判断
-d
检查文件是否存在且为目录文件-f
检查文件是否存在且为普通文件-S
检查文件是否存在且为socket文件-L
检查文件是否存在且为链接文件-O
检查文件是否存在并且被当前用户拥有-G
检查文件是否存在并且默认组为当前用户组
文件权限判断
-x
检查文件是否存在 && 可执行-w
检查文件是否存在 && 可写-r
检查文件是否存在 && 可读
文件内容判断
-nt
检查file1是否比file2新-ot
检查file1是否比file2旧-ef
检查file1是否与file2是同一个文件,判定依据的是i节点
6.8 数字表达式
-eq
相等-ne
不等于-ge
大于等于-gt
大于-lt
小于-le
小于等于
6.9 测试进阶表达式
我们可以将 [[ ]] 理解为增强版的 [ ],它不仅仅支持多表达式,还支持扩展正则表达式和通配符
格式
基本格式:
[[ 源内容 操作符 匹配内容 ]]
操作符解析:
== 左侧源内容可以被右侧表达式精确匹配
=~ 左侧源内容可以被右侧表达式模糊匹配
实例
[root@localhost day06]# string=value
[root@localhost day06]# [[ $string == value ]]
[root@localhost day06]# echo $?
0
[root@localhost day06]# [[ $string == value1 ]]
[root@localhost day06]# echo $?
1
[root@localhost day06]# [[ $string == v* ]]
[root@localhost day06]# echo $?
0
[root@localhost day06]# [[ $string == v"*" ]]
[root@localhost day06]# echo $?
1
[root@localhost day06]#
6.10 逻辑组合表达式
格式
方法1:
[ 条件1 -a 条件2 ] - 两个条件都为真,整体为真,否则为假
[ 条件1 -o 条件2 ] - 两个条件都为假,整体为假,否则为真
方法2:
[[ 条件1 && 条件2 ]] - 两个条件都为真,整体为真,否则为假
[[ 条件1 || 条件2 ]] - 两个条件都为假,整体为假,否则为真
实例
逻辑组合格式是限定的,如果使用符号[]
,内部判断必须使用-a
. 使用符号[[]]
, 内部判断必须使用&&
[root@localhost day06]# account=root;pwd=123456
[root@localhost day06]# echo ${account} ${pwd}
root 123456
[root@localhost day06]# [ ${account} == "root" -a ${pwd} == "123456" ]
[root@localhost day06]# echo $?
0
[root@localhost day06]# [ ${account} == "roo1" -a ${pwd} == "123456" ]
[root@localhost day06]# echo $?
1
[root@localhost day06]# [ ${account} == "roo1" -o ${pwd} == "123456" ]
[root@localhost day06]# echo $?
0
[root@localhost day06]# [[ ${account} == "root" && ${pwd} == "123456" ]]
[root@localhost day06]# echo $?
0
[root@localhost day06]# [[ ${account} == "root1" || ${pwd} == "123456" ]]
[root@localhost day06]# echo $?
0
[root@localhost day06]#