grep是行过滤工具;用于根据关键字对行进行过滤
> grep [选项] '关键字' 文件名
OPTIONS:
-i: 不区分大小写
-v: 查找不包含指定内容的行,反向选择
-w: 按单词搜索
-o: 打印匹配关键字
-c: 统计匹配到的行数
-n: 显示行号
-r: 逐层遍历目录查找
-A: 显示匹配行及后面多少行
-B: 显示匹配行及前面多少行
-C: 显示匹配行前后多少行
-l:只列出匹配的文件名
-L:列出不匹配的文件名
-e: 使用正则匹配
-E:使用扩展正则匹配
^key:以关键字开头
key$:以关键字结尾
^$:匹配空行
--color=auto :可以将找到的关键词部分加上颜色的显示
小扩展:颜色显示,使用
grep
时无需指定--color
参数即可高亮关键词(别名设置)临时设置: alias grep='grep --color=auto' //只针对当前终端和当前用户生效 永久设置: 1)全局(针对所有用户生效) vim /etc/bashrc alias grep='grep --color=auto' source /etc/bashrc 2)局部(针对具体的某个用户) vim ~/.bashrc alias grep='grep --color=auto' source ~/.bashrc ```
举例说明:
说明:不要直接使用/etc/passwd文件,将其拷贝到/tmp下做实验!
# grep -i root passwd 忽略大小写匹配包含root的行
# grep -w ftp passwd 精确匹配ftp单词
# grep -w hello passwd 精确匹配hello单词;自己添加包含hello的行到文件
# grep -wo ftp passwd 打印匹配到的关键字ftp
# grep -n root passwd 打印匹配到root关键字的行好
# grep -ni root passwd 忽略大小写匹配统计包含关键字root的行
# grep -nic root passwd 忽略大小写匹配统计包含关键字root的行数
# grep -i ^root passwd 忽略大小写匹配以root开头的行
# grep bash$ passwd 匹配以bash结尾的行
# grep -n ^$ passwd 匹配空行并打印行号
# grep ^# /etc/vsftpd/vsftpd.conf 匹配以#号开头的行
# grep -v ^# /etc/vsftpd/vsftpd.conf 匹配不以#号开头的行
# grep -A 5 mail passwd 匹配包含mail关键字及其后5行
# grep -B 5 mail passwd 匹配包含mail关键字及其前5行
# grep -C 5 mail passwd 匹配包含mail关键字及其前后5行
cut是列截取工具,用于列的截取
语法:
cut 选项 文件名
常见选项:
-c: 以字符为单位进行分割,截取
-d: 自定义分隔符,默认为制表符\t
-f: 与-d一起使用,指定截取哪个区域
举例说明:
# cut -d: -f1 1.txt 以:冒号分割,截取第1列内容
# cut -d ' ' -f1,6,7 1.txt 以空格分割,截取第1,6,7列内容
# cut -c4 1.txt 截取文件中每行第4个字符
# cut -c1-4 1.txt 截取文件中每行的1-4个字符
# cut -c5- 1.txt 从第5个字符开始截取后面所有字符
sort工具用于排序;它将文件的每一行作为一个单位,从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出。
-u :去除重复行
-r :降序排列,默认是升序
-o : 将排序结果输出到文件中,类似重定向符号>
-n :以数字排序,默认是按字符排序
-t :分隔符
-k :第N列
-b :忽略前导空格。
-R :随机排序,每次运行的结果均不同
举例说明
# sort -n -t: -k3 1.txt 按照用户的uid进行升序排列
# sort -nr -t: -k3 1.txt 按照用户的uid进行降序排列
# sort -n 2.txt 按照数字排序
# sort -nu 2.txt 按照数字排序并且去重
# sort -n 2.txt -o 3.txt 按照数字排序并将结果重定向到文件
uniq用于去除连续的重复行
常见选项:
-i: 忽略大小写
-c: 统计重复行次数
-d: 只显示重复行
tee工具是从标准输入读取并写入到标准输出和文件,即:双向覆盖重定向(屏幕输出|文本输入)
选项:
-a: 双向追加重定向
# echo hello world|tee file1
diff工具用于逐行比较文件的不同
注意:diff 描述两个文件不同的方式是告诉我们怎样改变第一个文件之后与第二个文件匹配。
语法:
diff [选项] 文件1 文件2
常用选项:
-b: 不检查空格
-B: 不检查空白行
-i: 不检查大小写
-w: 忽略所有的空格
--normal: 正常格式显示(默认)
-c: 上下文格式显示
-u: 合并格式显示
-q: 仅显示有无差异,不显示详细的信息
举例说明:
比较两个普通文件异同,文件准备:
> cat file1
aaaa
111
> cat file2
aaa
合并格式显示:
> diff -u file1 file2
# 前两行主要列出需要比较的文件名和文件的时间戳;文件名前面的符号---表示file1,+++表示file2
--- aaa.txt 2021-04-14 10:24:50.000000000 +0800
+++ bbb.txt 2021-04-14 10:25:02.000000000 +0800
@@ -1,2 +1 @@ # -1,2 表示aaa.txt的1-2行; +1 表示bbb.txt的1行; 这两者相比较
-aaaa # -表示删除
-111
+aaa # +表示新增
比较两个目录不同
> diff -q dir1 dir2
Only in dir1: file4
Only in dir2: test1
其他小技巧:
有时候我们需要以一个文件为标准,去修改其他文件,并且修改的地方较多时,我们可以通过打补丁的方式完成。
# 1)先找出文件不同,然后输出到一个文件
> diff -uN file1 file2 > file.patch
-u: 合并上下文模式
-N: 将不存在的文件当作空文件
# 2)将不同内容打补丁到文件
> patch file1 file.patch
patching file file1
# 3)测试验证
> diff file1 file2
paste 工具用于合并两个文件的文件行(file1第一行后面接file2第一行)
常用选项:
-d:自定义间隔符,默认是tab
-s:串行处理,非并行(第一行全第一个文件,第二行全第二个文件)
合并两个文件,将file2追加到file1后面:
> cat file1 file2 > file1 > cat file2 >> file1
tr
用于字符转换,替换和删除;主要用于删除文件中控制字符或进行字符转换
语法:
用法1:命令的执行结果交给tr处理,其中string1用于查询,string2用于转换处理
> commands|tr 'string1' 'string2'
用法2:tr处理的内容来自文件,记住要使用"<"标准输入
> tr 'string1' 'string2' < filename
用法3:根据选项匹配 string1 进行相应操作,如删除操作
> tr [options] 'string1' < filename
常用选项:
-d 删除字符串1中所有输入字符。
-s 删除所有重复出现字符序列,只保留第一个;即将重复出现字符串压缩为一个字符串 "abcaaa" > "abca"
常匹配字符串:
字符串 | 含义 | 备注 |
---|---|---|
a-z或[:lower:] | 匹配所有小写字母 | 所有大小写和数字[a-zA-Z0-9] |
A-Z或[:upper:] | 匹配所有大写字母 | |
0-9或[:digit:] | 匹配所有数字 | |
[:alnum:] | 匹配所有字母和数字 | |
[:alpha:] | 匹配所有字母 | |
[:blank:] | 所有水平空白 | |
[:punct:] | 匹配所有标点符号 | |
[:space:] | 所有水平或垂直的空格 | |
[:cntrl:] | 所有控制字符 | \f Ctrl-L 走行换页 \n Ctrl-J 换行 \r Ctrl-M 回车 \t Ctrl-I tab键 |
举例说明:
> cat 3.txt 自己创建该文件用于测试
ROOT:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
aaaaaaaaaaaaaaaaaaaa
bbbbbb111111122222222222233333333cccccccc
hello world 888
666
777
999
# tr -d '[:/]' < 3.txt 删除文件中的:和/
# cat 3.txt |tr -d '[:/]' 删除文件中的:和/
# tr '[0-9]' '@' < 3.txt 将文件中的数字替换为@符号
# tr '[a-z]' '[A-Z]' < 3.txt 将文件中的小写字母替换成大写字母
# tr -s '[a-z]' < 3.txt 匹配小写字母并将重复的压缩为一个
# tr -s '[a-z0-9]' < 3.txt 匹配小写字母和数字并将重复的压缩为一个
# tr -d '[:digit:]' < 3.txt 删除文件中的数字
# tr -d '[:blank:]' < 3.txt 删除水平空白
# tr -d '[:space:]' < 3.txt 删除所有水平和垂直空白
Tab 只能补全命令和文件 (RHEL6/Centos6)base-complete
^c 终止前台运行的程序
^z 将前台运行的程序挂起到后台(暂停运行)
^d 退出 等价exit
^l 清屏
^a |home 光标移到命令行的最前端
^e |end 光标移到命令行的后端
^u 删除光标前所有字符
^k 删除光标后所有字符
^r 搜索历史命令
*: 匹配0或多个任意字符
?: 匹配任意单个字符
[list]: 匹配[list]中的任意单个字符,或者一组单个字符 [a-z]
[!list]: 匹配除list中的任意单个字符
{string1,string2,...}:匹配string1,string2或更多字符串
> touch file{1..3}:创建文件:file1,file2,file3
> touch file{{1..3},5}:创建文件:file1,file2,file3,file5
""
:会把引号的内容当成整体来看待,允许通过 $
符号引用其他变量值''
:会把引号的内容当成整体来看待,禁止引用其他变量值,shell 中特殊符号都被视为普通字符``
: 反撇号和 $()
一样,引号或括号里的命令会优先执行,如果存在嵌套,反撇号不能用> echo "$(hostname)"
server
> echo '$(hostname)'
$(hostname)
> echo $(date +%F)
2018-11-22
> echo `date +%F`
2018-11-22
简单来说,shell 就是将需要执行的命令保存到文本中,按照顺序执行。它是解释型的,意味着不需要编译。把重复化、复杂化的工作,通过把工作的命令写成脚本,以后仅仅需要执行脚本就能完成这些工作。例如:
> cat /etc/shells
/bin/sh #是bash的一个快捷方式
/bin/bash #bash是大多数Linux默认的shell,包含的功能几乎可以涵盖shell所有的功能
/sbin/nologin #表示非交互,不能登录操作系统
/bin/dash #小巧,高效,功能相比少一些
/bin/csh #具有C语言风格的一种shell,具有许多特性,但也有一些缺陷
/bin/tcsh #是csh的增强版,完全兼容csh
1)脚本第一行,使用魔法字符 #!
指定解释器【必写】
#!/bin/bash
:表示以下内容使用 bash
解释器解析注意:如果直接将解释器路径写死在脚本里,可能在某些系统就会存在找不到解释器的兼容性问题,所以可以使用:
#!/bin/env 解释器
(例如:#!/bin/env bash
)
自动的在你的用户
PATH
变量中所定义的目录中寻找 解释器 来执行的
2)脚本第二部分,注释(#
)说明,对脚本的基本信息进行描述【可选】
3)脚本第三部分,脚本要实现的具体代码内容
标准脚本执行方法(建议)
#1) 编写shell脚本
> cat first_shell.sh
#!/bin/env bash
echo "hello world"
#2) 脚本增加可执行权限
> chmod +x first_shell.sh
#3) 标准方式执行脚本
# 绝对路径执行脚本
> /shell01/first_shell.sh
# 相对路径执行脚本
> ./first_shell.sh
注意:标准执行方式脚本必须要有可执行权限。
非标准的执行方法(不建议)
常用选项:
-x: 一般用于排错,查看脚本的执行过程
-n: 用来查看脚本的语法是否有问题
> bash first_shell.sh
> sh first_shell.sh
> bash -x first_shell.sh
+ echo 'hello world'
hello world
source
命令读取脚本文件,执行文件里的代码> source first_shell.sh
hello world
> A="hello world" #定义变量A
> echo $A #调用变量A
hello world
> echo ${A} #还可以这样调用,不管你的姿势多优雅,总之要给钱
hello world
> unset A #取消变量
> A=1234567
> echo $A
1234567
> echo ${A:2:4} 表示从A变量中第3个字符开始截取,截取4个字符
3456
$变量名
和 ${变量名}
的异同:
${变量名}
可以只截取变量的一部分,而 $变量名
不可以> B=`date +%F`
> echo $B
2019-04-16
> C=$(uname -r)
> echo $C
2.6.32-696.el6.x86_64
通过终端让用户自己给变量赋值,比较灵活。
语法:read [选项] 变量名
常见选项:
选项 | 释义 |
---|---|
-p prompt | 定义提示用户的信息 |
-n | 定义字符数(限制变量值的长度) |
-s | 不显示(不显示用户输入的内容) |
-t timeout | 定义超时时间,默认单位为秒(限制用户输入变量值的超时时间) |
举例说明:
> read -p "Input your name:" name
Input your name:tom
> echo $name
tom
> cat 1.txt
10.1.1.1 255.255.255.0
> read ip mask < 1.txt
> echo $ip
10.1.1.1
> echo $mask
255.255.255.0
给变量做一些限制,固定变量的类型,比如:整型、只读
用法:declare 选项 变量名=变量值
常用选项:
选项 | 释义 | 举例 |
---|---|---|
-i | 将变量看成整数 | declare -i A=123 |
-r | 定义只读变量 | declare -r B=hello |
-a | 定义普通数组;查看普通数组 | |
-A | 定义关联数组;查看关联数组 | |
-x | 将变量通过环境导出(定义环境变量) | declare -x AAA=123456 等于 export AAA=123456 |
env
:查看系统的环境变量set
:查询当前用户的所有变量(本地变量与环境变量)export 变量名=变量值
:定义环境变量(或者 变量名=变量值;export 变量名
)全局变量:全局所有的用户和程序都能调用,且继承,新建的用户也默认能调用.
解读相关配置文件
文件名 | 说明 | 备注 |
---|---|---|
$HOME/.bashrc |
当前用户的bash信息,用户登录时读取 | 定义用户的别名、umask、函数等 |
$HOME/.bash_profile |
当前用户的环境变量,用户登录时读取 | 定义用户的环境变量 |
$HOME/.bash_logout |
当前用户退出当前shell时最后读取 | 定义用户退出时执行的程序等 |
/etc/bashrc |
全局的bash信息,所有用户都生效 | 系统和所有用户都生效,用来定义全局的别名、umask、函数等 |
/etc/profile |
全局环境变量信息 | 系统和所有用户都生效,用来定义全局变量 |
说明:以上文件修改后,都需要重新 source
让其生效或者退出重新登录。
/etc/profile
$HOME/.bash_profile
$HOME/.bashrc
/etc/bashrc
$HOME/.bash_logout
内置变量 | 含义 |
---|---|
$? |
上一条命令执行后返回的状态;状态值为0表示执行正常,非0表示执行异常或错误 |
$0 | 当前执行的程序或脚本名 |
$# |
脚本后面接的参数的个数 |
$* |
脚本后面所有参数,参数当成一个整体输出,每一个变量参数之间以空格隔开 |
$@ |
脚本后面所有参数,参数是独立的,也是全部输出 |
$1~$9 |
脚本后面的位置参数,$1表示第1个位置参数,依次类推 |
${10}~${n} |
扩展位置参数,第10个位置变量必须用{}大括号括起来(2位数字以上扩起来) |
$$ |
当前所在进程的进程号,如echo $$ |
$! | 后台运行的最后一个进程号 (当前终端) |
!$ | 调用最后一条命令历史中的参数 |
进一步了解 $*
和 $@
的区别:
$*
:表示将变量看成一个整体
$@
:表示变量是独立的
#!/bin/bash
for i in "$@"
do
echo $i
done
echo "======我是分割线======="
for i in "$*"
do
echo $i
done
> bash 3.sh a b c
a
b
c
======我是分割线=======
a b c
算术运算:默认情况下,shell 就只能支持简单的整数运算
运算内容:加(+)、减(-)、乘(*)、除(/)、求余数(%)
表达式 | 说明 | 举例 |
---|---|---|
$(( )) | echo $((1+1)) | |
$[ ] | echo $[10-5] | |
expr 表达式 | 用空格隔开每个项; 用反斜杠 \ 放在 shell 特定的字符前面;表达式之间必须加空格 |
expr 10 / 5 expr 10 * 2 |
let 表达式 | 变量计算中不需要加上 $ 来表示变量;表达式中间不能有空格 |
n=1;let n+=1 (n+=1 等价于 n=n+1)let n=n**3(n 的3次方) let n++ |
bc | 计算小数 | echo 1+1.5 | bc 执行 bc 命令进入交互模式:1+1.5 |
数组名[索引下标]=值
array[0]=v1
array[1]=v2
array[2]=v3
array[3]=v4
数组名=(值1 值2 值3 ...)
array=(var1 var2 var3 var4)
array1=(`cat /etc/passwd`) 将文件中每一行赋值给array1数组
array2=(`ls /root`)
array3=(harry amy jack "zhang san")
array4=(1 2 3 4 "hello world" [10]=linux)
${数组名[元素下标]}
echo ${array[0]} 获取数组里第一个元素
echo ${array[*]} 获取数组里的所有元素
echo ${#array[*]} 获取数组里所有元素个数
echo ${!array[@]} 获取数组元素的索引下标
echo ${array[@]:1:2} 访问指定的元素;1代表从下标为1的元素开始获取;2代表获取后面几个元素
查看普通数组信息:
> declare -a
declare -A 数组名
declare -A asso_array1
declare -A asso_array2
declare -A asso_array3
# 数组名[索引or下标]=变量值
> asso_array1[linux]=one
> asso_array1[java]=two
> asso_array1[php]=three
> asso_array2=([name1]=harry [name2]=jack [name3]=amy [name4]="Miss Hou")
> declare -A
declare -A asso_array1='([php]="three" [java]="two" [linux]="one" )'
declare -A asso_array2='([name3]="amy" [name2]="jack" [name1]="harry" [name4]="Miss Hou" )'
> echo ${asso_array1[linux]}
one
> echo ${asso_array1[php]}
three
> echo ${asso_array1[*]}
three two one
> echo ${!asso_array1[*]}
php java linux
> echo ${#asso_array1[*]}
3
> echo ${#asso_array2[*]}
4
> echo ${!asso_array2[*]}
name3 name2 name1 name4
> declare -A books
> let books[linux]++
> declare -A|grep books
declare -A books='([linux]="1" )'
> let books[linux]++
> declare -A|grep books
declare -A books='([linux]="2" )'
dirname
和 basename
dirname
和 basename
> A=/root/Desktop/shell/mem.txt
> echo $A
/root/Desktop/shell/mem.txt
> dirname $A 取出目录
/root/Desktop/shell
> basename $A 取出文件
mem.txt
一个“%”代表从右往左删除
两个“%%”代表从右往左去掉最多
一个“#”代表从左往右去掉删除
两个“##”代表从左往右去掉最多
举例说明:
> url=www.taobao.com
> echo ${#url} #14 获取变量的长度
> echo ${url#*.} #taobao.com
> echo ${url##*.} #com
> echo ${url%.*} #www.taobao
> echo ${url%%.*} #www
/:从左往右第一个
//:替代所有
> echo ${url/ao/AO} #www.tAObao.com
> echo ${url//ao/AO} #www.tAObAO.com
替代: -
和 :-
、+
和:+
${变量名-新的变量值} 或者 ${变量名=新的变量值}
变量没有被赋值:会使用“新的变量值“ 替代
变量有被赋值(包括空值): 不会被替代
> echo ${abc-123}
> abc=hello
> echo ${abc-444}
> echo $abc
> abc=
> echo ${abc-222}
${变量名:-新的变量值} 或者 ${变量名:=新的变量值}
变量没有被赋值或者赋空值:会使用“新的变量值“ 替代
变量有被赋值: 不会被替代
> echo ${ABC:-123}
> ABC=HELLO
> echo ${ABC:-123}
> ABC=
> echo ${ABC:-123}
${变量名:+新的变量值}
变量没有被赋值:不会使用“新的变量值“ 替代
变量有被赋值(包括空值): 会被替代
> echo ${abc=123}
> echo ${abc:=123}
> unset abc
> echo ${abc:+123}
> abc=hello
> echo ${abc:+123}
123
> abc=
> echo ${abc:+123}
${变量名+新的变量值}
变量没有被赋值或者赋空值:不会使用“新的变量值“ 替代
变量有被赋值: 会被替代
> unset abc
> echo ${abc+123}
> abc=hello
> echo ${abc+123}
123
> abc=
> echo ${abc+123}
123
${变量名?新的变量值}
变量没有被赋值:提示错误信息
变量被赋值(包括空值):不会使用“新的变量值“ 替代
> unset abc
> echo ${abc?123}
-bash: abc: 123
> abc=hello
> echo ${abc?123}
hello
> abc=
> echo ${abc?123}
${变量名:?新的变量值}
变量没有被赋值或者赋空值时:提示错误信息
变量被赋值:不会使用“新的变量值“ 替代
说明:?主要是当变量没有赋值提示错误信息的,没有赋值功能
> unset abc
> echo ${abc:?123}
-bash: abc: 123
> abc=hello
> echo ${abc:?123}
hello
> abc=
> echo ${abc:?123}
-bash: abc: 123
test 条件表达式
[ 条件表达式 ]
(注意中括号与表达式之间有空格)[[ 条件表达式 ]]
支持正则(注意中括号与表达式之间有空格)判断参数 | 含义 |
---|---|
-e | 判断文件是否存在(任何类型文件) |
-f | 判断文件是否存在并且是一个普通文件 |
-d | 判断文件是否存在并且是一个目录 |
-L | 判断文件是否存在并且是一个软连接文件 |
-b | 判断文件是否存在并且是一个块设备文件 |
-S | 判断文件是否存在并且是一个套接字文件 |
-c | 判断文件是否存在并且是一个字符设备文件 |
-p | 判断文件是否存在并且是一个命名管道文件 |
-s | 判断文件是否存在并且是一个非空文件(有内容) |
举例说明:
test -e file 只要文件存在条件为真
[ -d /shell01/dir1 ] 判断目录是否存在,存在条件为真
[ ! -d /shell01/dir1 ] 判断目录是否存在,不存在条件为真
[[ -f /shell01/1.sh ]] 判断文件是否存在,并且是一个普通的文件
判断参数 | 含义 |
---|---|
-r | 当前用户对其是否可读 |
-w | 当前用户对其是否可写 |
-x | 当前用户对其是否可执行 |
-u | 是否有suid,高级权限冒险位 |
-g | 是否sgid,高级权限强制位 |
-k | 是否有t位,高级权限粘滞位 |
说明:这里的新旧指的是文件的修改时间。
判断参数 | 含义 |
---|---|
file1 -nt file2 | 比较file1是否比file2新 |
file1 -ot file2 | 比较file1是否比file2旧 |
file1 -ef file2 | 比较是否为同一个文件,或者用于判断硬连接,是否指向同一个inode |
判断参数 | 含义 |
---|---|
-eq | 相等 |
-ne | 不等 |
-gt | 大于 |
-lt | 小于 |
-ge | 大于等于 |
-le | 小于等于 |
数值比较
> [ 1 -eq 2 ];echo $?
> [ `id -u` -eq 0 ];echo $?
> [ $(id -u) -eq 0 ] && echo this is root
类C风格的数值比较
注意:在(( ))中,=表示赋值;==表示判断
> ((1==2));echo $?
> ((1<2));echo $?
> ((`id -u`==0));echo $?
判断参数 | 含义 |
---|---|
-z | 判断是否为空字符串,字符串长度为0则成立 |
-n | 判断是否为非空字符串,字符串长度不为0则成立 |
string1 = string2 或者 string1 == string2 |
判断字符串是否相等 |
string1 != string2 | 判断字符串是否相不等 |
> a='hello world';b=world
> [ $a = $b ];echo $?
> [ "$a" = "$b" ];echo $?
> [ "$a" == "$b" ];echo $?
> [ "$a" != "$b" ];echo $?
> [ '' = $a ];echo $?
-bash: [: : unary operator expected
2
> [[ '' = $a ]];echo $?
0
判断符号 | 含义 | 举例 |
---|---|---|
-a 和 && | 逻辑与 | [ $(id -u) -eq 1 -a 1 -ne 0 ] [ 1 -eq 1 ] && [ 1 -ne 0 ] |
-o 和 || | 逻辑或 | [ 1 -eq 1 -o 1 -ne 1 ] |
特别说明:
&&
前面的表达式为真,才会执行后面的代码||
前面的表达式为假,才会执行后面的代码;
只用于分割命令或表达式;
和 &&
和 ||
都可以用来分割命令或者表达式;
完全不考虑前面的语句是否正确执行,都会执行 ;
号后面的内容&&
符号,需要考虑 &&
前面的语句的正确性,前面语句正确执行才会执行 &&
后的内容;反之亦然||
符号,需要考虑 ||
前面的语句的非正确性,前面语句执行错误才会执行 ||
后内容;反之亦然&&
和 ||
一起出现,按照以上原则,从左往右依次执行if [ condition ];then
command
command
fi
if test 条件;then
命令
fi
if [[ 条件 ]];then
命令
fi
[ 条件 ] && command
if [ condition ];then
command1
else
command2
fi
[ 条件 ] && command1 || command2
if [ condition1 ];then
command1
elif [ condition2 ];then
command2
else
command3
fi
判断当前主机是否和远程主机是否ping通
#!/bin/env bash
# 该脚本用于判断当前主机是否和远程指定主机互通
# 交互式定义变量,让用户自己决定ping哪个主机
read -p "请输入你要ping的主机的IP:" ip
# 使用ping程序判断主机是否互通 -c指定ping的次数
ping -c1 $ip &>/dev/null
if [ $? -eq 0 ];then
echo "当前主机和远程主机$ip是互通的"
else
echo "当前主机和远程主机$ip不通的"
fi
# 逻辑运算符
# test $? -eq 0 && echo "当前主机和远程主机$ip是互通的" || echo "当前主机和远程主机$ip不通的"
判断web服务器中httpd进程是否存在
#!/bin/env bash
# 判断一个程序(httpd)的进程是否存在
pgrep httpd &>/dev/null
if [ $? -ne 0 ];then
echo "当前httpd进程不存在"
else
echo "当前httpd进程存在"
fi
或者
test $? -eq 0 && echo "当前httpd进程存在" || echo "当前httpd进程不存在"
补充命令
pgrep命令:以名称为依据从运行进程队列中查找进程,并显示查找到的进程id
选项
-o:仅显示找到的最小(起始)进程号;
-n:仅显示找到的最大(结束)进程号;
-l:显示进程名称;
-P:指定父进程号;pgrep -p 4764 查看父进程下的子进程id
-g:指定进程组;
-t:指定开启进程的终端;
-u:指定进程的有效用户ID。
判断门户网站是否能够正常访问
#!/bin/env bash
# 判断门户网站是否能够正常提供服务
#定义变量
web_server=www.baidu.com
#访问网站
wget -P /shell/ $web_server &>/dev/null
[ $? -eq 0 ] && echo "当前网站服务是ok" && rm -f /shell/index.* || echo "当前网站服务不ok,请立刻处理"
循环体: do…done之间的内容
列表 for 循环:用于将一组命令执行**已知的次数**
for variable in {list}
do
command
command
…
done
或者
for variable in a b c
do
command
command
done
> for var in {1..10};do echo $var;done
> for var in 1 2 3 4 5;do echo $var;done
> for var in `seq 10`;do echo $var;done
> for var in {0..10..2};do echo $var;done # {起始..结尾..步长}
> for var in {2..10..2};do echo $var;done
> for var in {10..1};do echo $var;done
> for var in {10..1..-2};do echo $var;done
> for var in `seq 10 -2 1`;do echo $var;done # seq 起始 步长 结尾
不带列表的 for 循环,执行时将用户指定参数和参数的个数当做列表
for variable
do
command
command
…
done
#!/bin/bash
for var
do
echo $var
done
echo "脚本后面有$#个参数"
# expr1:定义变量并赋初值
# expr2:决定是否进行循环(条件)
# expr3:决定循环变量如何改变,决定循环什么时候退出
for(( expr1;expr2;expr3 ))
do
command
command
…
done
for (( i=1;i<=5;i++))
do
echo $i
done
continue
:继续;表示循环体内下面的代码不执行,重新开始下一次循环break
:打断;马上停止执行本次循环,执行循环体后面的代码exit
:表示直接跳出程序shift
:使位置参数向左移动,默认移动1位,可以使用 shift 2
(参考案例2)> cat for5.sh
#!/bin/bash
for i in {1..5}
do
test $i -eq 2 && break || touch /tmp/file$i
done
echo hello
写一个脚本,局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里
以10.1.1.1~10.1.1.10为例
#!/bin/bash
#定义变量
ip=10.1.1
#循环去ping主机的IP
for ((i=1;i<=10;i++))
do
ping -c1 $ip.$i &>/dev/null
if [ $? -eq 0 ];then
echo "$ip.$i is ok" >> /tmp/ip_up.txt
else
echo "$ip.$i is down" >> /tmp/ip_down.txt
fi
# 或者
# [ $? -eq 0 ] && echo "$ip.$i is ok" >> /tmp/ip_up.txt || echo "$ip.$i is down" >> /tmp/ip_down.txt
done
> time ./ping.sh
ip is ok....
./ping.sh 0.01s user 0.03s system 0% cpu 1:50.50 total
> cat aa.sh
#!/bin/bash
sum=0
while [ $# -ne 0 ]
do
let sum=$sum+$1
shift
done
echo sum=$sum
> ./aa.sh 1 2 3 4 5
并行执行:
{程序}&
:表示将程序放到后台并行执行,如果需要等待程序执行完毕再进行下面内容,需要加 wait
#!/bin/bash
#定义变量
ip=10.1.1
#循环去ping主机的IP
for ((i=1;i<=10;i++))
do
{
ping -c1 $ip.$i &>/dev/null
if [ $? -eq 0 ];then
echo "$ip.$i is ok" >> /tmp/ip_up.txt
else
echo "$ip.$i is down" >> /tmp/ip_down.txt
fi
}&
done
wait
echo "ip is ok...."
> time ./ping.sh
ip is ok....
./ping.sh 0.02s user 0.03s system 0% cpu 11.026 total
特点:条件为真就进入循环;条件为假就退出循环
while 表达式
do
command...
done
# 从文件中获取参数,以空格分隔
while read 参数1 参数2
do
useradd $user
echo $pass|passwd --stdin $user
done < 文件
#!/bin/bash
#定义变量
count=0
ntp_server=10.1.1.1
while true
do
rdate -s $ntp-server &>/dev/null
if [ $? -ne 0 ];then
echo "system date failed" |mail -s 'check system date' root@localhost
else
let count++
if [ $[$count%100] -eq 0 ];then
echo "system date successfull" |mail -s 'check system date' root@localhost && count=0
fi
fi
sleep 3
done
特点:条件为假就进入循环;条件为真就退出循环
until 表达式
do
command
command
...
done
#!/bin/bash
i=1
until [ $i -gt 10 ]
do
if [ $i -le 5 ];then
useradd -u $[1000+$i] stu$i && echo 123|passwd --stdin stu$i
else
[ ! -d /rhome ] && mkdir /rhome
useradd -d /rhome/stu$i stu$i && echo 123|passwd --stdin stu$i
fi
let i++
done
#课程目标
系统变量:RANDOM,默认会产生 0~32767
的随机整数
# 打印一个随机数
> echo $RANDOM
# 查看系统上一次生成的随机数
> set | grep RANDOM
RANDOM=28325
#产生0~100内的随机数
> echo $[$RANDOM%101]
#产生50-100之内的随机数
> echo $[$RANDOM%51+50]
#产生三位数的随机数
> echo $[$RANDOM%900+100]
#!/bin/bash
#定义变量
file=/shell03/text.txt
#循环选出5行
for ((i=1;i<=5;i++))
do
#定位随机行号
total=`wc -l $file |cut -d' ' -f1`
line_num=$[RANDOM%$total+1]
#取出行号对应的行
str=`head -$line_num $file|tail -1`
#显示到屏幕
echo $str
#删除已经被抽取的行
#sed -i "/$line_num/d" $file
done
参考博客:https://blog.csdn.net/liumiaocn/article/details/86715953
交互式的命令行:比如 sftp
或者 oracle
的 sqlplus
,或者 mysql
的命令控制台,以 sftp
为例子,当我们输入 sftp 用户名@sftp服务器
登录之后,需要在 sftp>
的提示下进行各种 sftp
命令的操作。
命令 << 分隔串 # 分割串常见的为EOF,但不一定固定为EOF,可以使用开发者自行定义的,比如END
# 缺省方式下第一个分割串(EOF)前后均可有空格或者tab,运行时会自动剔除,不会造成影响
字符串1
…
字符串n
分隔串 # 缺省方式下第二个分割串(EOF)必须顶格写,前后均不可有空格或者tab
# 简单打印
cat << EOF
> hello
> world
> EOF
hello
world
# 内容写入文件
cat << end >herehelloworld.c
#include
void main(){
printf("hello world by using here document\n");
}
end
使用 '
或者 "
或者 \
对第一个 EOF
进行封装,可以对命令中的变量转义,使其原样输出
# 变量未转义
> cat << eof
heredoc> aaa
heredoc> $bbb
heredoc> $ccc
heredoc> ddd
heredoc> eof
aaa
ddd
>
# 变量转义后:
> cat << 'eof'
heredoc> aaa
heredoc> $bbb
heredoc> $ccc
heredoc> ddd
heredoc> eof
aaa
$bbb
$ccc
ddd
使用 <<-
代替 <<
唯一的作用在于分割串所扩起来的内容和第二个分隔符,顶格的 tab
会被删除
# 使用 <<
> cat << eof
heredoc> 前面是tab
heredoc> 前面是两个空格
heredoc> eof # 当eof前有tab时,无法结束
heredoc> eof # 当eof前有空格时,无法结束
heredoc> eof # eof顶格写,才能结束
前面是tab
前面是两个空格
eof
eof
# 使用 <<-
> cat <<- eof
heredocd> 前面是tab
heredocd> 前面是两个空格
heredocd> eof # 当eof前有空格时,无法结束
heredocd> eof # 当eof前有tab时,tab会被删除,然后结束输入
前面是tab
前面是两个空格
eof
vim
中使用命令:set list
查看文档内的特殊字符
expect
是一个自动化交互套件,主要应用于执行命令和程序时,系统以交互形式要求输入指定字符串,实现交互通信。
expect常用命令总结:
spawn 交互程序开始后面跟命令或者指定程序
expect 获取匹配信息匹配成功则执行expect后面的程序动作
send exp_send 用于发送指定的字符串信息
exp_continue 在expect中多次匹配就需要用到
send_user 用来打印输出 相当于shell中的echo
exit 退出expect脚本
eof expect执行结束 退出
set 定义变量
puts 输出变量
set timeout 设置超时时间
interact 交互,表示接下来让用户自己去和服务器交互
格式:set 变量名 变量值
#!/usr/bin/expect
set ip 10.1.1.1
set pass 123456
set timeout 5
格式:[ lindex $argv 参数下标 ]
#!/usr/bin/expect
set ip [ lindex $argv 0 ]
set pass [ lindex $argv 1 ]
expect {
# 当遇到期望值时,发送命令;
# exp_continue 用来表示多次匹配
# 命令输出完后,使用 \r 或者 \n 换行
"期望值1" { send "命令1\r";exp_continue }
"期望值2" { send "命令2\r" }
}
#!/usr/bin/expect
# 开启一个程序
spawn ssh [email protected]
# 捕获相关内容
expect {
"(yes/no)?" { send "yes\r";exp_continue }
"password:" { send "123456\r" }
}
interact #交互,表示接下来让用户自己去和服务器交互,如果不写,则程序执行完会退出登录的服务器
#!/usr/bin/expect
set ip 10.1.1.1
set pass 123456
set timeout 5
spawn ssh root@$ip
expect {
"yes/no" { send "yes\r";exp_continue }
"password:" { send "$pass\r" }
}
expect "#"
send "rm -rf /tmp/*\r"
send "touch /tmp/file{1..3}\r"
send "date\r"
send "exit\r"
expect eof
1. 循环 useradd username
2. 登录远程主机——>ssh——>从ip.txt文件里获取IP和密码分别赋值给两个变量
3. 使用expect程序来解决交互问题
#!/bin/bash
# 循环在指定的服务器上创建用户和文件
while read ip pass
do
# -END 指定结束标志,当看到END时,表示expect执行完毕,也可以指定其它字符串,-表示删除命令前的 tab
/usr/bin/expect <<-END &>/dev/null
# 注意:需要交互的脚本应放在 expect 中
spawn ssh root@$ip
expect {
"yes/no" { send "yes\r";exp_continue }
"password:" { send "$pass\r" }
}
expect "#" { send "useradd yy1;rm -rf /tmp/*;exit\r" }
expect eof
END
echo "$ip服务器用户创建完毕"
done < ip.txt
注意:
expect
中yum install -y expect
说明:pattern表示需要匹配的模式
case var in 定义变量;var代表是变量名
pattern 1) 模式1;用 | 分割多个模式,相当于or
command1 需要执行的语句
;; 两个分号代表命令结束
pattern 2)
command2
;;
pattern 3)
command3
;;
*) default,不满足以上模式,默认执行*)下面的语句
command4
;;
esac esac表示case语句结束
具体需求:
脚本提示让用户输入需要管理的服务名,然后提示用户需要对服务做什么操作,如启动,关闭等操作
#!/bin/env bash
read -p "请输入你要管理的服务名称(vsftpd):" service
case $service in
vsftpd|ftp)
read -p "请选择你需要做的事情(restart|stop):" action
case $action in
stop|S)
service vsftpd stop &>/dev/null && echo "该$serivce服务已经停止成功"
;;
start)
service vsftpd start &>/dev/null && echo "该$serivce服务已经成功启动"
;;
esac
;;
httpd|apache)
echo "apache hello world"
;;
*)
echo "请输入你要管理的服务名称(vsftpd)"
;;
esac
具体需求:
模拟一个多任务维护界面;当执行程序时先显示总菜单,然后进行选择后做相应维护监控操作
**********请选择*********
h 显示命令帮助
f 显示磁盘分区
d 显示磁盘挂载
m 查看内存使用
u 查看系统负载
q 退出程序
*************************
思路:
落地实现:
#!/bin/env bash
cat <<-EOF
h 显示命令帮助
f 显示磁盘分区
d 显示磁盘挂载
m 查看内存使用
u 查看系统负载
q 退出程序
EOF
#!/bin/bash
#打印菜单
cat <<-EOF
h 显示命令帮助
f 显示磁盘分区
d 显示磁盘挂载
m 查看内存使用
u 查看系统负载
q 退出程序
EOF
#让用户输入需要的操作
while true
do
read -p "请输入需要操作的选项[f|d]:" var1
case $var1 in
h)
cat <<-EOF
h 显示命令帮助
f 显示磁盘分区
d 显示磁盘挂载
m 查看内存使用
u 查看系统负载
q 退出程序
EOF
;;
f)
fdisk -l
;;
d)
df -h
;;
m)
free -m
;;
u)
uptime
;;
q)
exit
;;
esac
done
#!/bin/bash
#打印菜单
menu(){
cat <<-END
h 显示命令帮助
f 显示磁盘分区
d 显示磁盘挂载
m 查看内存使用
u 查看系统负载
q 退出程序
END
}
menu
while true
do
read -p "请输入你的操作[h for help]:" var1
case $var1 in
h)
menu
;;
f)
read -p "请输入你要查看的设备名字[/dev/sdb]:" var2
case $var2 in
/dev/sda)
fdisk -l /dev/sda
;;
/dev/sdb)
fdisk -l /dev/sdb
;;
esac
;;
d)
lsblk
;;
m)
free -m
;;
u)
uptime
;;
q)
exit
;;
esac
done
方法1:
函数名()
{
函数体(一堆命令的集合,来实现某个功能)
}
方法2:
function 函数名()
{
函数体(一堆命令的集合,来实现某个功能)
}
函数中return说明:
> cat fun1.sh
#!/bin/bash
hello(){
echo "hello lilei $1"
hostname
}
menu(){
cat <<-EOF
1. mysql
2. web
3. app
4. exit
EOF
}
> source fun1.sh
> . fun1.sh
> hello 888
hello lilei 888
MissHou.itcast.cc
> menu
1. mysql
2. web
3. app
4. exit
> vim ~/.bashrc
文件中增加如下内容:
hello(){
echo "hello lilei $1"
hostname
}
menu(){
cat <<-EOF
1. mysql
2. web
3. app
4. exit
EOF
}
注意:
当用户打开bash的时候会读取该文件
#!/bin/bash
#打印菜单
source ./fun1.sh
menu(){
cat <<-END
h 显示命令帮助
f 显示磁盘分区
d 显示磁盘挂载
m 查看内存使用
u 查看系统负载
q 退出程序
END
}
menu //调用函数
具体需求:
思路:
交互式定义多个变量来保存用户信息 姓名、性别、年龄
如果不输一直提示输入
根据用户输入信息做出匹配判断
代码实现:
#!/bin/bash
#该函数实现用户如果不输入内容则一直循环直到用户输入为止,并且将用户输入的内容打印出来
input_fun()
{
input_var=""
output_var=$1
while [ -z $input_var ]
do
read -p "$output_var" input_var
done
echo $input_var
}
input_fun 请输入你的姓名:
或者
#!/bin/bash
fun()
{
read -p "$1" var
if [ -z $var ];then
fun $1
else
echo $var
fi
}
#调用函数并且获取用户的姓名、性别、年龄分别赋值给name、sex、age变量
name=$(input_fun 请输入你的姓名:)
sex=$(input_fun 请输入你的性别:)
age=$(input_fun 请输入你的年龄:)
#根据用户输入的性别进行匹配判断
case $sex in
man)
if [ $age -gt 18 -a $age -le 35 ];then
echo "中年大叔你油腻了吗?加油"
elif [ $age -gt 35 ];then
echo "保温杯里泡枸杞"
else
echo "年轻有为。。。"
fi
;;
woman)
xxx
;;
*)
xxx
;;
esac
扩展延伸:
描述以下代码含义:
:()
{
:|:&
}
:
现有的跳板机虽然实现了统一入口来访问生产服务器,yunwei用户权限太大可以操作跳板机上的所有目录文件,存在数据被误删的安全隐患,所以希望你做一些安全策略来保证跳板机的正常使用。
欢迎使用Jumper-server,请选择你要操作的主机:
1. DB1-Master
2. DB2-Slave
3. Web1
4. Web2
h. help
q. exit
#!/bin/bash
# jumper-server
# 定义菜单打印功能的函数
menu()
{
cat <<-EOF
欢迎使用Jumper-server,请选择你要操作的主机:
1. DB1-Master
2. DB2-Slave
3. Web1
4. Web2
h. help
q. exit
EOF
}
# 屏蔽以下信号
trap '' 1 2 3 19
# 调用函数来打印菜单
menu
#循环等待用户选择
while true
do
# 菜单选择,case...esac语句
read -p "请选择你要访问的主机:" host
case $host in
1)
ssh root@10.1.1.1
;;
2)
ssh root@10.1.1.2
;;
3)
ssh root@10.1.1.3
;;
h)
clear;menu
;;
q)
exit
;;
esac
done
将脚本放到yunwei用户家目录里的.bashrc里执行:
bash ~/jumper-server.sh
exit
进一步完善需求
为了进一步增强跳板机的安全性,工作人员通过跳板机访问生产环境,但是不能在跳板机上停留。
#!/bin/bash
#公钥推送成功
trap '' 1 2 3 19
#打印菜单用户选择
menu(){
cat <<-EOF
欢迎使用Jumper-server,请选择你要操作的主机:
1. DB1-Master
2. DB2-Slave
3. Web1
4. Web2
h. help
q. exit
EOF
}
#调用函数来打印菜单
menu
while true
do
read -p "请输入你要选择的主机[h for help]:" host
#通过case语句来匹配用户所输入的主机
case $host in
1|DB1)
ssh root@10.1.1.1
;;
2|DB2)
ssh root@10.1.1.2
;;
3|web1)
ssh root@10.1.1.250
;;
h|help)
clear;menu
;;
q|quit)
exit
;;
esac
done
自己完善功能:
1. 用户选择主机后,需要事先推送公钥;如何判断公钥是否已推
2. 比如选择web1时,再次提示需要做的操作,比如:
clean log
重启服务
kill某个进程
回顾信号:
1) SIGHUP 重新加载配置
2) SIGINT 键盘中断^C
3) SIGQUIT 键盘退出
9) SIGKILL 强制终止
15) SIGTERM 终止(正常结束),缺省信号
18) SIGCONT 继续
19) SIGSTOP 停止
20) SIGTSTP 暂停^Z
正则表达式(Regular Expression、regex或regexp,缩写为RE),也译为正规表示法、常规表示法,是一种字符模式,用于在查找过程中匹配指定的字符。
许多程序设计语言都支持利用正则表达式进行字符串操作。例如,在Perl中就内建了一个功能强大的正则表达式引擎。
正则表达式这个概念最初是由Unix中的工具软件(例如sed和grep)普及开的。
支持正则表达式的程序如:locate |find| vim| grep| sed |awk
元字符
指那些在正则表达式中具有特殊意义的专用字符,如:点(.) 星(*) 问号(?)等
前导字符
位于元字符前面的字符. ab**c*** aoo**o.**
元字符 | 功能 | 备注 |
---|---|---|
. | 匹配除了换行符以外的任意单个字符 | |
* | 前导字符出现0次或连续多次 | |
.* | 任意长度字符 | ab.* |
^ | 行首(以…开头) | ^root |
$ | 行尾(以…结尾) | bash$ |
^$ | 空行 | |
[] | 匹配括号里任意单个字符或一组单个字符 | [abc] |
[^] | 匹配不包含括号里任一单个字符或一组单个字符 | [^abc] |
^[] |
匹配以括号里任意单个字符或一组单个字符开头 | ^[abc] |
\^[\^] |
匹配不以括号里任意单个字符或一组单个字符开头 | \^\[^abc] |
# cat 1.txt
ggle
gogle
google
gooogle
goooooogle
gooooooogle
taobao.com
taotaobaobao.com
jingdong.com
dingdingdongdong.com
10.1.1.1
Adfjd8789JHfdsdf/
a87fdjfkdLKJK
7kdjfd989KJK;
bSKJjkksdjf878.
cidufKJHJ6576,
hello world
helloworld yourself
元字符 | 功能 | 备注 |
---|---|---|
< | 取单词的头 | |
> | 取单词的尾 | |
< > | 精确匹配 | |
{n} | 匹配前导字符连续出现n次 | |
{n,} | 匹配前导字符至少出现n次 | |
{n,m} | 匹配前导字符出现n次与m次之间 | |
( ) | 保存被匹配的字符 | |
\d | 匹配数字(grep -P) | [0-9] |
\w | 匹配字母数字下划线(grep -P) | [a-zA-Z0-9_] |
\s | 匹配空格、制表符、换页符(grep -P) | [\t\r\n] |
举例说明:
需求:将10.1.1.1替换成10.1.1.254
1)vim编辑器支持正则表达式
> vim 1.txt
:%s#\(10.1.1\).1#\1.254#g
:%s/\(10.1.1\).1/\1.254/g
2)sed支持正则表达式【后面学】
> sed -n 's#\(10.1.1\).1#\1.254#p' 1.txt
10.1.1.254
说明:
找出含有10.1.1的行,同时保留10.1.1并标记为标签1,之后可以使用\1来引用它。
最多可以定义9个标签,从左边开始编号,最左边的是第一个。
需求:将helloworld yourself 换成hellolilei myself
> vim 1.txt
:%s#\(hello\)world your\(self\)#\1lilei my\2#g
> sed -n 's/\(hello\)world your\(self\)/\1lilei my\2/p' 1.txt
hellolilei myself
> sed -n 's/helloworld yourself/hellolilei myself/p' 1.txt
hellolilei myself
> sed -n 's/\(hello\)world your\(self\)/\1lilei my\2/p' 1.txt
hellolilei myself
Perl内置正则:
\d 匹配数字 [0-9]
\w 匹配字母数字下划线[a-zA-Z0-9_]
\s 匹配空格、制表符、换页符[\t\r\n]
> grep -P '\d' 1.txt
> grep -P '\w' 2.txt
> grep -P '\s' 3.txt
grep:必须加 -E 或者使用 egrep
sed:必须加 -r
扩展元字符 | 功能 | 备注 |
---|---|---|
+ | 匹配一个或多个前导字符 | bo+ 匹配boo、 bo |
? | 匹配零个或一个前导字符 | bo? 匹配b、 bo |
| | 或 | 匹配a或b |
() | 组字符(看成整体) | (my|your)self:表示匹配myself或匹配yourself |
{n} | 前导字符重复n次 | |
{n,} | 前导字符重复至少n次 | |
{n,m} | 前导字符重复n到m次 |
举例说明:
> grep "root|ftp|adm" /etc/passwd
> egrep "root|ftp|adm" /etc/passwd
> grep -E "root|ftp|adm" /etc/passwd
> grep -E 'o+gle' test.txt
> grep -E 'o?gle' test.txt
> egrep 'go{2,}' 1.txt
> egrep '(my|your)self' 1.txt
使用正则过滤出文件中的IP地址:
> grep '[0-9]\{2\}\.[0-9]\{1\}\.[0-9]\{1\}\.[0-9]\{1\}' 1.txt
10.1.1.1
> grep '[0-9]{2}\.[0-9]{1}\.[0-9]{1}\.[0-9]{1}' 1.txt
> grep -E '[0-9]{2}\.[0-9]{1}\.[0-9]{1}\.[0-9]{1}' 1.txt
10.1.1.1
> grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' 1.txt
10.1.1.1
> grep -E '([0-9]{1,3}\.){3}[0-9]{1,3}' 1.txt
10.1.1.1
表达式 | 功能 | 示例 |
---|---|---|
[:alnum:] | 字母与数字字符 | [[:alnum:]]+ |
[:alpha:] | 字母字符(包括大小写字母) | [[:alpha:]]{4} |
[:blank:] | 空格与制表符 | [[:blank:]]* |
[:digit:] | 数字 | [[:digit:]]? |
[:lower:] | 小写字母 | [[:lower:]]{4,} |
[:upper:] | 大写字母 | [[:upper:]]+ |
[:punct:] | 标点符号 | [[:punct:]] |
[:space:] | 包括换行符,回车等在内的所有空白 | [[:space:]]+ |
> grep -E '^[[:digit:]]+' 1.txt
> grep -E '^[^[:digit:]]+' 1.txt
> grep -E '[[:lower:]]{4,}' 1.txt
把握一个原则,让你轻松搞定可恶的正则符号:
元字符:在正则中,具有特殊意义的专用字符,如: 星号(*)、加号(+)等
前导字符:元字符前面的字符叫前导字符
元字符 | 功能 | 示例 |
---|---|---|
* | 前导字符出现0次或者连续多次 | ab* abbbb |
. | 除了换行符以外,任意单个字符 | ab. ab8 abu |
.* | 任意长度的字符 | ab.* adfdfdf |
[] | 括号里的任意单个字符或一组单个字符 | [abc][0-9][a-z] |
[^] | 不匹配括号里的任意单个字符或一组单个字符 | [^abc] |
^[] | 匹配以括号里的任意单个字符开头 | ^[abc] |
^[^] | 不匹配以括号里的任意单个字符开头 | |
^ | 行的开头 | ^root |
$ | 行的结尾 | bash$ |
^$ | 空行 | |
{n}和{n} | 前导字符连续出现n次 | [0-9]{3} |
{n,}和{n,} | 前导字符至少出现n次 | [a-z]{4,} |
{n,m}和{n,m} | 前导字符连续出现n-m次 | go{2,4} |
<> | 精确匹配单词 | |
() | 保留匹配到的字符 | (hello) |
+ | 前导字符出现1次或者多次 | [0-9]+ |
? | 前导字符出现0次或者1次 | go? |
| | 或 | ^root|^ftp |
() | 组字符 | (hello|world)123 |
\d | perl内置正则 | grep -P \d+ |
\w | 匹配字母数字下划线 |
要求如下:
参考脚本:
参考:
#!/bin/bash
conf=/etc/httpd/conf/httpd.conf
input_fun()
{
input_var=""
output_var=$1
while [ -z $input_var ]
do
read -p "$output_var" input_var
done
echo $input_var
}
ipaddr=$(input_fun "Input Host ip[192.168.0.1]:")
web_host_name=$(input_fun "Input VirtualHostName [www.test.cc]:")
root_dir=$(input_fun "Input host Documentroot dir:[/var/www/html]:")
[ ! -d $root_dir ] && mkdir -p $root_dir
chown apache.apache $root_dir && chmod 755 $root_dir
echo this is $web_host_name > $root_dir/index.html
echo "$ipaddr $web_host_name" >> /etc/hosts
[ -f $conf ] && cat >> $conf <<end
NameVirtualHost $ipaddr:80
$ipaddr:80>
ServerAdmin webmaster@$web_host_name
DocumentRoot $root_dir
ServerName $web_host_name
ErrorLog logs/$web_host_name-error_log
CustomLog logs/$web_host_name-access_loh common
</VirtualHost>
end
写一个脚本,将跳板机上yunwei用户的公钥推送到局域网内可以ping通的所有机器上
说明:主机和密码文件已经提供
10.1.1.1:123456
10.1.1.2:123456
功能1:管理员root创建yunwei用户和安装expect软件包
#!/bin/env bash
# 实现批量推送公钥
# 判断jumper上的yunwei账号是否存在
{
id yunwei
[ $? -ne 0 ] && useradd yunwei && echo 123|passwd --stdin yunwei
} &>/dev/null
#判断expect程序是否安装
rpm -q expect
[ $? -ne 0 ] && yum -y install expect && echo "expect软件已经成功安装"
功能2:判断主机是否ping通并且yunwei用户推送公钥
#!/bin/env bash
# 判断yunwei用户密钥对是否存在
home_dir=/home/yunwei
[ ! -f $home_dir/.ssh/id_rsa.pub ] && ssh-keygen -P '' -f id_rsa &>/dev/null
#循环检查主机的网络并且进行公钥推送
ip_txt=$home_dir/ip.txt
for i in `cat $ip_txt`
do
ip=`echo $i|cut -d: -f1`
pass=`echo $i|cut -d: -f2`
ping -c1 $ip &>/dev/null
if [ $? -eq 0 ];then
echo $ip >> ~/ip_up.txt
/usr/bin/expect <<-END &>/dev/null
spawn ssh-copy-id root@$ip
expect
{
"(yes/no)" { send "yes\n";exp_continue }
"password:" { send "$pass\n" }
}
expect eof
END
else
echo $ip >> $home_dir/ip_down.txt
fi
done
# 测试验证
remote_ip=`head -1 ~/ip_up.txt`
ssh root@$remote_ip hostname
[ $? -eq 0 ] && echo "公钥推送成功"
jumper-server 有yunwei用户
yunwei用户sudo授权:
visudo
## Allow root to run any commands anywhere
root ALL=(ALL) ALL
yunwei ALL=(root) NOPASSWD:ALL,!/sbin/shutdown,!/sbin/init,!/bin/rm -rf /
解释说明:
1)第一个字段yunwei指定的是用户:可以是用户名,也可以是别名。每个用户设置一行,多个用户设置多行,也可以将多个用户设置成一个别名后再进行设置。
2)第二个字段ALL指定的是用户所在的主机:可以是ip,也可以是主机名,表示该sudo设置只在该主机上生效,ALL表示在所有主机上都生效!限制的一般都是本机,也就是限制使用这个文件的主机;一般都指定为"ALL"表示所有的主机,不管文件拷到那里都可以用。比如:10.1.1.1=...则表示只在当前主机生效。
3)第三个字段(root)括号里指定的也是用户:指定以什么用户身份执行sudo,即使用sudo后可以享有所有root账号下的权限。如果要排除个别用户,可以在括号内设置,比如ALL=(ALL,!oracle,!pos)。
4)第四个字段ALL指定的是执行的命令:即使用sudo后可以执行所有的命令。除了关机和删除根内容以外;也可以设置别名。NOPASSWD: ALL表示使用sudo的不需要输入密码。
5)也可以授权给一个用户组
%admin ALL=(ALL) ALL 表示admin组里的所有成员可以在任何主机上以任何用户身份执行任何命令
#!/bin/bash
#判断公钥是否存在
[ ! -f /home/yunwei/.ssh/id_rsa ] && ssh-keygen -P '' -f ~/.ssh/id_rsa
#循环判断主机是否ping通,如果ping通推送公钥
tr ':' ' ' < /shell04/ip.txt|while read ip pass
do
{
ping -c1 $ip &>/dev/null
if [ $? -eq 0 ];then
echo $ip >> ~/ip_up.txt
/usr/bin/expect <<-END &>/dev/null
spawn ssh-copy-id root@$ip
expect {
"yes/no" { send "yes\r";exp_continue }
"password:" { send "$pass\r" }
}
expect eof
END
fi
}&
done
wait
echo "公钥已经推送完毕,正在测试...."
#测试验证
remote_ip=`tail -1 ~/ip_up.txt`
ssh root@$remote_ip hostname &>/dev/null
test $? -eq 0 && echo "公钥成功推送完毕"
写一个脚本,统计web服务的不同连接状态个数
ss -natp|grep :80
#!/bin/bash
#count_http_80_state
#统计每个状态的个数
declare -A array1
states=`ss -ant|grep 80|cut -d' ' -f1`
for i in $states
do
let array1[$i]++
done
#通过遍历数组里的索引和元素打印出来
for j in ${!array1[@]}
do
echo $j:${array1[$j]}
done