一:逻辑运算
true(1), false(0)
与运算:
1 与 1 = 1
1 与 0 = 0
0 与 1 = 0
0 与 0 = 0
或运算:
1 或1 = 1
1 或0 = 1
0 或1 = 1
0 或0 = 0
非运算:
! 1 = 0
! 0 = 1
短路与:&&
第一个为0,结果必定为0
第一个为1,第二个必须要参与运算
短路或:||
第一个为1,结果必定为1
第一个为0,第二个必须要参与运算
异或:^
异或的两个值,相同为假,不同为真
二:条件测试(test与[])
条件测试是指判断某需求是否满足,需要由测试机制来实现。专用的测试表达式需要由测试命令辅助完成测试过程
评估布尔声明,以便用在条件性执行中
若真,则返回0
若假,则返回1
测试命令:(test与[]是等价的)
test EXPRESSION
[ EXPRESSION ]
[[ EXPRESSION ]]
注意:EXPRESSION前后必须有空白字符
当我们要测试数值大小时,我们要用一下的表达式
-gt是否大于
-ge是否大于等于
-eq是否等于
-ne是否不等于
-lt是否小于
-le是否小于等于
例子:
test 11 -eq 011 && echo "相同"
[ 11 -eq 011 ] && echo "相同"(两式等价)
[ "$A"=="$B" ]&& echo "相同" ||echo "不同"(当前面的测试通过时,执行&&后的命令,测试不通过时,执行||之后的命令)
当我们测试的内容是字符串时,我们要用以下的表达式:
== 是否等于
> ascii码是否大于ascii码
< 是否小于
! =是否不等于
=~ 左侧字符串是否能够被右侧的PATTERN所匹配
注意: 此表达式一般用于[[ ]]中;扩展的正则表达式
-z "STRING“字符串是否为空,空为真,不空为假
-n "STRING“字符串是否不空,不空为真,空为假
注意:用于字符串比较时的用到的操作数都应该使用引号
例子:
1.编写脚本/root/bin/argsnum.sh,接受一个文件路径作为参数;如果参数个数不等于1,则提示用户“应该给一个参数”,并立即退出;如果参数个数等于1,则显示所指向的文件中的空白行数
#!/bin/bash
[ $# -ne 1 ] && echo "应该给一个参数" || echo "$(cat $1 |egrep -c "^[[:space:]]*$")"
2.编写脚本/root/bin/hostping.sh,接受一个主机的IPv4地址做为参数,如果未给定一个合法的IP地址,则提示 “给一个合法的IPV4地址” ,并立即退出。如果给出IPV4地址,则测试是否可连通。如果能ping通,则提示用户“该IP地址可访问”;如果不可ping通,则提示用户“该IP地址不可访问”
echo $1 |egrep -q "\<(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]2[0-4][0-9]|25[0-5])\>" && ( ping -c1 -w1 $1 &>/dev/null && echo "主机网络畅通" || echo “网络不可用” ) || echo "输入IP有误,格式:xxx.xxx.xxx.xxx,xxx小于255"
3、编写脚本/root/bin/checkdisk.sh,检查磁盘分区空间和inode使用率,如果超过80%,就发广播警告空间将满
#!/bin/bash
u1=$(df|grep /dev/sd |tr -s " " :|cut -d: -f5|cut -d% -f1 |sort -rn|head -1)
u2=$(df -i|grep /dev/sd |tr -s " " :|cut -d: -f5|cut -d% -f1 |sort -rn|head -1)
[ $u1 -gt 80 ] && wall "发警告"|| [ $u2 -gt 80 ] && wall "发警告" || echo "安全"
二:文件测试:
存在性测试
-a FILE:同-e
-e FILE: 文件存在性测试,存在为真,否则为假
存在性及类别测试
-b FILE:是否存在且为块设备文件
-c FILE:是否存在且为字符设备文件
-d FILE:是否存在且为目录文件
-f FILE:是否存在且为普通文件
-h FILE 或-L FILE:存在且为符号链接文件
-p FILE:是否存在且为命名管道文件
-S FILE:是否存在且为套接字文件
文件权限测试:
-r FILE:是否存在且可读
-w FILE: 是否存在且可写
-x FILE: 是否存在且可执行
文件特殊权限测试:
-u FILE:是否存在且拥有suid权限
-g FILE:是否存在且拥有sgid权限
-k FILE:是否存在且拥有sticky权限
文件大小测试:
-s FILE: 是否存在且非空
文件是否打开:
-t fd: fd表示文件描述符是否已经打开且与某终端相关
-N FILE:文件自动上一次被读取之后是否被修改过
-O FILE:当前有效用户是否为文件属主
-G FILE:当前有效用户是否为文件属组
双目测试:
FILE1 -ef FILE2: FILE1与FILE2是否指向同一个设备上的相同inode
FILE1 -nt FILE2: FILE1是否新于FILE2(mtime)
FILE1 -ot FILE2: FILE1是否旧于FILE2
例子
[ -z “$HOSTNAME” -o $HOSTNAME "=="localhost.localdomain" ] && hostname www.magedu.com
([ -z “$HOSTNAME” -o $HOSTNAME "=="localhost.localdomain" ]等价于[ -z "$HOSTNAME" ]||[ "$HOSTNAME"=="localhost.localdomain" ])
[ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab
( [ -f /bin/cat -a -x /bin/cat ]等价于[ -f /bin/cat ]&&[ -x /bin/cat ])
1、编写脚本/bin/per.sh,判断当前用户对指定的参数文件,是否不可读并且不可写
#!/bin/bash
if [ ! -r $1 ]&&[ ! -w $1 ]
then
echo "$1是不可读不可写文件"
elif [ -r $1 ]&&[ -w $1 ]
then
echo "$1是可读可写文件"
elif [ -w $1 ]&&[ ! -r $1 ]
then
echo "$1是不可读可写文件"
else
echo "$1是可读不可写文件"
fi
2、编写脚本/root/bin/excute.sh ,判断参数文件是否为sh后缀的普通文件,如果是,添加所有人可执行权限,否则提示用户非脚本文件
#!/bin/bash
if [[ $1 =~ .*\.sh ]]
then
chmod a+x $1
else
echo "非脚本文件"
fi
3、编写脚本/root/bin/nologin.sh和login.sh,实现禁止和充许普通用户登录系统
#!/bin/bash
if id $1 &> /dev/null && [ $1 != root ]
then
usermod -s /sbin/nologin $1
elif [ $1 == root ]
then
echo "这是root用户"
fi
#!/bin/bash
if id $1 &> /dev/null && [ $1 != root ]
then
usermod -s /bin/bash $1
elif [ $1 == root ]
then
echo "这是root用户"
fi
4.read命令:把输入值分配给一个或多个shell变量
-p指定要显示的提示
-s 静默输入,一般用于密码(等价于stty -echo)
-n N 指定输入的字符长度N
-d‘字符’ 输入结束符
-t N TIMEOUT为N秒
注意:read从标准输入中读取值,给每个单词分配一个变量所有剩余单词都被分配给最后一个变量
5.转译:使随后的字符按原意解释
转译有以下方式 '';\和""。不过这三种转译也是不一样的:首先""和''是范围转译,一次能转译多个字符,\一次只能转译一个字符。然后,''和\是完全转译,""在遇到!\`$这四种情况下是不转译的!
三:交互式登录和非交互式登录
1.bash的配置文件
全局配置:
/etc/profile
/etc/profile.d/*.sh
/etc/bashrc
个人配置:
~/.bash_profile
~/.bashrc
2.交互式与非交互式登录方式及区别
交互式登录:完整的登录方式,需要账户密码
(1)直接通过终端输入账号密码登录
(2)使用“su - UserName”切换的用户
非交互式登录:
(1)suUserName
(2)图形界面下打开的终端
(3)执行脚本
(4)任何其它的bash实例
交互式与非交互式登录方式的区别
(1)交互式登录重新读取文件来获取别名,变量等不会继承上一个shell的变量。非交互式登录首先继承上一个shell的所有变量,再去读取文件,而且读取的文件比交互式登录读取的文件少。
(2)交互式文件读取文件的顺序:/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile--> ~/.bashrc--> /etc/bashrc
(3)非交互式文件读取文件的顺序:~/.bashrc--> /etc/bashrc--> /etc/profile.d/*.sh
实验:(1)在/etc/profile下添加变量A=A1,在/etc/profile.d/目录下创建wangkai.sh文件,并添加变量B=B2,在用户wangkai家目录下修改.bash_profile 文件,添加变量C=C3,接着修改文件.bash_rc添加变量D=D4,最后在/etc/bashrc下添加变量E=E5,交互式登录root用户,结果如图:
解析:这是因为root用户登录时会访问/etc/profile,/etc/profile.d/*.sh, /etc/bashrc这三个文件,而访问不到用户wangkai的文件所以输出这三个变量。
(2)修改/etc/profile文件A=A6,不切换用户啊,再次输出变量。结果如图
从图上发现内容不变是因为我们没有切换用户,没有读取文件,所以内容保持不变。
(3)非交互式登录用户root,在输出变量,发现内容不变,这是因为非交互式登录继承上一个shell的所有变量,所以虽然他不访问/etc/profile文件但也有该变量
(4)退出该子shell,修改/etc/profile.d/wangkai.sh下变量B=B7,非交互式登录登录root 输出变量结果如下图:
这是因为非交互式登录用户root,首先继承变量A=A6,B=B2,E=E5 ,之后再读取文件/etc/profile.d/wangkai.sh,覆盖变量B=B2,而变量E=E5在文件中不变,所以结果便如上图所示。
(5)退出该shell,非交互式登录用户wangkai,再输出变量。再退出shell,交互式登录用户wangkai,输出变量,结果如图。
3.文件分类
profile类:为交互式登录的shell提供配置
全局:/etc/profile, /etc/profile.d/*.sh
个人:~/.bash_profile
作用:
(1) 用于定义环境变量
(2) 运行命令或脚本
bashrc类:为非交互式和交互式登录的shell提供配置
全局:/etc/bashrc
个人:~/.bashrc
作用:
(1) 定义命令别名和函数
(2) 定义本地变量
修改profile和bashrc文件后生效的两种方法:
1重新启动shell进程
2 . 或source(在当前shell下有效,区别于bash ..和./执行后面的会开辟子shell来执行,不会对当前shell产生影响。)
4.~/.bash_logout文件在退出登录shell时运行可以用于创建自动备份和清除临时文件
5练习:
5.1.让所有用户的PATH环境变量的值多出一个路径,例如:/usr/local/apache/bin
注意:要将该目录写在/etc/profile下,写完后用.或source运行即可,还要注意格式PATH=$PATH:/usr/local/apache/bin
5.2用户root登录时,将命令指示符变成红色,并自动启用如下别名:
rm=‘rm –i’
cdnet=‘cd /etc/sysconfig/network-scripts/’
editnet=‘vim /etc/sysconfig/network-scripts/ifcfg-eth0’
editnet=‘vim /etc/sysconfig/network-scripts/ifcfg-eno16777736 或 ifcfg-ens33 ’ (如果系统是CentOS7)
注意:要在当前用户家目录下的.bashrc下加进去,在用source命令执行。
5.3、编写用户的环境初始化脚本reset.sh,包括别名,登录提示符,vim的设置,环境变量等
一旦执行reset.sh,会设置以下内容
创建一个别名为ipconfig功能是显示第一个网卡的IP
设置提示符为绿色
设置vim自动显示行号
设置登录后的欢迎界面(内容自定义)
#!/bin/bash
2 if id $1 &>/dev/null && [ $1 != root ]
3 then
4 cat <
5 alias ipconfig='ifconfig ens33|grep "inet\>"|tr -s " " :|cut -d: -f3'
6 EOF
7 echo 'PS1="\[\e[32m\][\u@\h \W]\\$\[\e[0m\] " '>>/home/$1/.bashrc
8 echo 'set number'>>/etc/vimrc
9 echo '你好,世界'>>/etc/motd
10 source /home/$1/.bashrc
11 elif id $1 &>/dev/null && [ $1 == root ]
12 then
13 cat <
14 alias ipconfig='ifconfig ens33|grep "inet\>"|tr -s " " :|cut -d: -f3'
15 EOF
16 echo 'PS1="\[\e[32m\][\u@\h \W]\\$\[\e[0m\] " '>>/root/.bashrc
17 echo 'set number'>>/etc/vimrc
18 echo '你好,世界'>> /etc/motd
19 source /root/.bashrc
20 else
21 echo "没有该用户"
22 fi
5.4、编写一个创建用户的脚本,要求以下功能
a.提示用户输入希望创建的用户名(当用户超时8秒不输入,提示超时并退出)
b.检测用户名是否已存在,若存在则提示用户名已存在,并退出。
c.用户创建完成后提示用户是否要继续设置密码,若用户输入yes、YES、y、Y时则继续下一步,如输入其他,或超时8秒均退出。
d.接上一步,为用户设置密码,首先提示用户输入要设置的密码,密码的输入过程不可见。
e.对用户上一步所输入的密码进行长度检测,若少于5位(包含5位),则提示用户密码太短,并退出。
f.对用户在第d步所输入的密码进行复杂度检测,若所输入的内容与/usr/share/dict/words 字典中的某一行条目完全一致,则提示密码是一个常见单词,并退出。
g.再一次让用户输入密码,若第二次输入的密码与在第d步输入的不一致,则提示用户两次密码不一致并退出。
h.d至g步骤全部通过后,为用户设置密码后,并提示密码已成功设置。最后正确退出。
以上的所有退出情况应给出不同的返回值。
#!/bin/bash
13 read -p "请输入用户名 " -t 8 userName
14 if id $userName &>/dev/null ;then
15 echo "该用户已存在";exit 1
16 else
17 useradd $userName
18 read -p "是否继续设置密码? " -t 8 mima
19 if [ $mima == yes ]||[ $mima == YES ]||[ $mima == y ]||[ $mima == Y ];then
20 read -t 8 -sp "输入密码 " mima1
21 lens=$(echo $mima1 |grep -o .|wc -l)
22 if [ $lens -lt 6 ] ;then
23 echo "太短";exit 2
24 else
25 pd=$(cat /usr/share/dict/words | egrep -o "^$mima1$")
26 if [ "$mima1" == "$pd" ];then
27 echo "常见";exit 3
28 else
29 read -sp "再次输入密码 " -t 8 mima2
30 if [ $mima1 != $mima2 ] ;then
31 echo "密码不一致 ";exit 4
32 else
33 echo $mima2 |passwd --stdin $userName &>/dev/null && echo "密码修改成功";exit 0
34 fi
35 fi
36
37 fi
38 fi
39 fi
40