egrep及扩展正则表达式
egrep = grep -E
语法:
egrep [OPTIONS] PATTERN [FILE...]
扩展正则表达式的元字符:
字符匹配:
(1) . :匹配任意单个字符
(2) [] :指定范围内的任意单个字符
(3) [^]:指定范围外的任意单个字符
次数匹配:
(1) * :匹配其前面的字符任意次
(2) ? :匹配其前面的字符0次或1次
(3) + :匹配其前面的字符1次或多次
(4) {m} :匹配其前面的字符m次
(5) {m,n}:至少m次,最多n次
锚定匹配:
(1) ^ :锚定行首
(2) $ :锚定行尾
(3) \<,\b :锚定词首
(4) \>,\b :锚定词尾
分组匹配:
(1) () :分组
(2) \1,\2,\3.... :后向引用
(3) | :或者,(a|b)=a 或 b
练习(使用扩展正则表达式):
1、显示当前系统root、centos或user1用户的默认shell和UID?
解:egrep "^(root|centos|user1)" /etc/passwd | cut -d: -f1,3,7
2、找出/etc/rc.d/init.d/functions文件中某单词后面跟一个小括号的行?
解:egrep -o "\<.*\>\(\)" /etc/init.d/functions
3、使用echo输出一个路径,使用egrep取出其基名?
解: echo /etc/sysconfig/network | egrep -o "[^/]+/?$"
4、找出ifconfig命令结果中1-255之间的数值?
解:ifconfig | egrep "\<([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-5][0-5])\>"
5、找出ifconfig结果中的IP地址?
解:ifconfig | egrep "([0-9]{1,3}\.){3}[0-9]{1,3}"
bash的基础特性(4)
bash中的变量的种类:
根据变量的生效范围等标准分成以下几种:
(1) 本地变量:生效范围为当前shell进程,当前shell关闭的话变量也就失效了
(2) 环境变量:生效范围为当前shell及其子shell进程
(3) 局部变量:生效范围为当前shell进程中某代码片段(通常指函数)
(4) 位置变量:$1,$2,$3...来表示,用于让脚本在脚本代码中用通过命令行传递给它的参数
(5) 特殊变量:$?(上条命令的执行结果状态),$0(命令本身),$*,$@,$#...
本地变量:
变量赋值: name='value'
可以使用引用:
value:
(1) 可以是直接字串
(2) 变量引用:name=$username
(3) 命令引用:name=`COMMAND`,name=$(COMMAND)
变量引用: ${name},$name
"":弱引用,其中的变量引用会被替换为变量值
'':强引用,其中的变量引用不会被替换为变量值,而保持原字符串
显示已定义的所有变量
set
销毁变量:
unset name
环境变量:
变量赋值:
export name='value'
declare -x name='value'
变量引用:${name},$name
显示所有环境变量:
export
env
printenv
销毁变量:
unset name
bash有许多内建的环境变量:PATH、SHELL、UID、HISTSIZE、HOME、PWD、OLD、HISTFILE、PS1
变量命名法则:
1、不能使用程序中的保留字:例如if,for
2、只能使用数字字母及下划线,且不能以数字开头
3、尽量做到见名知意
只读变量(不能被改值,不能被销毁):
readonly name
declare -r name
位置变量:
在脚本代码中调用通过命令行传递给脚本的参数
$1,$2,...:对应调用第1,2
shift [n]
$0:脚本本身(命令本身)
$*:传递给脚本的所有参数
$@:传递给脚本的所有参数
$#:传递给脚本的参数的个数
示例:判断给出的文件的行数
#!/bin/bash
linecount="$(wc -l $1 | cut -d' ' -f1 )"
echo "$1 has $linecount lines."
bash的配置文件
按生效范围划分为两类:
(1) 全局配置
/etc/prorifle
/etc/profile.d/*.sh
/etc/bashrc
(2) 个人配置
~/.bash_profile
~/.bashrc
按功能划分为两类:
(1) profile类:交互式登陆shell提供配置
全局:/etc/profile,/etc/profile.d/*.sh
个人:~/.bash_profile
功能:
(1) 用于定义环境变量
(2) 用于运行命令或脚本
(2) bashrc类:为非交互式登陆的shell提供配置
全局:/etc/bashrc
个人:~/.bashrc
功能:
(1) 定义命令别名
(2) 定义本地变量
shell登陆类别:
(1)交互式登陆:
直接通过终端输入账号密码登陆
使用 su - Username 或 su -l Username切换的用户
读取配置文件顺序:
/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc
(2)非交互式登陆:
su Username
图形界面下打开的终端
执行脚本
读取配置文件顺序:
~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh
编辑配置文件定义的新配置的生效方式:
(1) 重新启动shell进程
(2) source 或.命令进程
问题:
1、定义对所有用户都生效的别名,应该定义在哪个配置文件中?
解:/etc/bashrc
2、当所有用户登陆时都会收到提示信息在哪里定义?
解:/etc/profile.d/.sh
3、让用户的PATH环境变量的值多出一个路径,例如多出/usr/local/apache2/bin
管理员?
解:export PATH="$PATH:/usr/local/apache2/bin"
所有?
解:/etc/profile.d/.sh #手动创建一个后缀为.sh的文件,内容与上方相同
bash中的算数运算
+,-,*,/,%,**
# help let #查看关于算数的帮助
实现算数运算:
(1) let var=算数表达式
例:let test=1+2
(2) var=$[算数表达式]
例:test=$[2+3]
(3) var=$((算数表达式))
例:test=$((3+4))
(4) var=$(expr arg1 arg2 arg3...)
例:mul2=$(expr 2 \* 2)
Note:乘法符号有些场景中需要转义
bash有内建的随机数生成器:$RANDOM
例:echo $[RANDOM%60] #对60取模,0-60之间的随机数
增强型赋值:
OPER:+=,-=,*=,/=,%=
let varOPERvalue
例:
count=1
count=$[$count+1] #给count赋值count+1
=
let count+=1 #这个也相当与count在原有基础上+1再把结果赋值给count
=
let count++ #在count自身基础上+1并存回count
自增,自减:
let var+=1 #与let var++相同
let var++
let var-=1 #与let var--相同
let var--
练习1:写一个脚本
计算/etc/passwd文件中的第10个用户和第20个用户的ID之和
解:
#!/bin/bash
ten="$(head -n10 /etc/passwd | tail -n1 | cut -d: -f3)"
twenty="$(head -n20 /etc/passwd | tail -n1 | cut -d: -f3)"
let sum=$[ten+twenty]
echo "The Ten user UID + Twenty UID = $sum"
练习2:写一个脚本
传递两个文件路径作为参数给脚本,计算这两个文件中所有空白行之和
解:
#!/bin/bash
one=$(egrep "^[[:space:]]*$" $1 | wc -l)
two=$(egrep "^[[:space:]]*$" $2 | wc -l)
sum=$[one+two]
echo "The $1 space + $2 space sum is $sum"
练习3:写一个脚本
统计/etc,/var,/usr目录共有多少个一级子目录和文件:
解:
etc=$(ls -l /etc | wc -l)
var=$(ls -l /var | wc -l)
usrr=$(ls -l /usr | wc -l)
dirsum=$[etc+var+usr]
echo "The etc dir has $etc file and dir."
echo "The var dir has $var file and dir."
echo "The usr dir has $usr file and dir."
echo "The etc var usr dir sum is $dirsum"
条件测试:
判断某需求是否满足,需要由测试机制来实现
Note:专用的测试表达式需要由测试命令辅助完成测试过程
测试命令:
test 测试表达式
[ 测试表达式 ]
[[ 测试表达式 ]]
Note:中括号中的测试表达式,前后必须要有空格,否则语法错误
bash的测试类型:
(1) 数值测试
-gt :是否大于,是则为真,否则为假
-ge :是否大于等于,是则为真,否则为假
-eq :是否等于,是则为真,否则为假
-ne :是否不等于,是则为真,否则为假
-lt :是否小于,是则为真,否则为假
-le :是否小于等于,是则为真,否则为假
(2) 字符串测试
==/=:两端是否等于,常用
> :是否大于,ASCII编码表
< :是否小于,ASCII编码表
!= :是否不等于,是则为真,否则为假
=~ :左侧字符串是否能够被右侧模式匹配,是则为真,否则为假
此种表达式一般用于[[ ]]中
-z "字符串或变量" :测试变量是否为空,空则为真,不空则为假
-n "字符串或变量" :测试变量是否不空,不空则为真,不空则为假
Note:用于字符串比较时,用到的操作数,都应该使用引号
(3) 文件测试
存在性测试:
-e "文件路径":文件存在性测试,存在为真,否则为假
存在性及类别测试(并且关系):
-b "目标路径":目标存在且为块儿设备文件则为真,否则为假
-c "目标路径":目标存在且为字符设备文件则为真,否则为假
-d "目标路径":目标存在且为目录则为真,否则为假
-f "目标路径":目标存在且为普通文件则为真,否则为假
-p "目标路径":目标存在且为命名管道文件则为真,否则为假
-S "目标路径":目标存在且为套接字文件则为真,否则为假
文件权限测试:
-r "目标路径":目标存在且拥有读权限则为真,否则为假
-w "目标路径":目标存在且拥有写权限则为真,否则为假
-x "目标路径":目标存在且拥有执行权限则为真,否则为假
文件特殊权限测试:
-g "目标路径":目标存在且拥有sgid权限则为真,否则为假
-u "目标路径":目标存在且拥有suid权限则为真,否则为假
-k "目标路径":目标存在且拥有sticky权限则为真,否则为假
文件大小测试:
-s "目标路径":目标存在且非空则为真,否则为假
文件打开性测试:
-t fd: fd表示文件描述符是否已经打开且与某终端相关
-N "目标路径":文件自从上一次被读取之后是否被修改过
-O "目标路径":当前用户是否为文件属主
-G "目标路径":当前用户是否为文件属组
双目测试:
FILE1 -ef FILE2: FILE1与FILE2是否指向同一个设备上的inode
FILE1 -nt FILE2: FILE1是否比FILE2更新
FILE1 -ot FILE2: FILE1是否比FILE2旧
组合测试条件:
逻辑运算:
第一种方式:
COMMAND1 && COMMAND2
[ -e FILE ] && [ -r FILE ] #目标存在且可读
COMMAND1 || COMMAND2
! COMMAND
第二种方式:
[ EXPRESSION1 -a EXPRESSION2 ] #与运算
[ EXPRESSION1 -o EXPRESSION2 ] #或运算
! EXPRESSION #非运算
必须使用测试命令进行
示例:
[ -z "$hostname" -o "$hostname" == "bogon" ] && hostname kaikai
#判断$hostname是否为空或者是否等于bogon,如果前面两条任意一个满足则执行后续命令
[ -e /bin/cat -a -x /bin/cat ] && cat /etc/fstab
#判断/bin/cat是否存在并且是否可执行,如果前面两条都满足则执行后续命令
[ ! -r /app/grub2.cfg -a ! -w /app/grub2.cfg ] && echo true || echo fail
#当前用户为root的话任何条件都是无效的,针对执行此命令的用户判断
bash自定义退出状态码:
exit number:自定义退出状态码
注意:脚本中一旦遇到exit命令,脚本会立即终止,终止退出状态取决于exit命令后面的数字
注意2:如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码
练习:写一个脚本
接收一个文件路径作为参数:
如果参数个数小于1,则提示用户"至少应该给一个参数",并立即退出
如果参数个数不小于1,则显示第一个参数所指向的文件中的空白行数
解:
#!/bin/bash
[ $# -lt 1 ] && echo "please input a arg " && exit 1
space=$(egrep "^[[:space:]]*$" $1 | wc -l)
[ $# -ge 1 ] && echo "The $1 space is $space"