shell脚本基础
linux中常见的shell
-
bash:基于gun的框架下发展的shell
-
csh:类似c语言的shell
-
tcsh:整合了csh提供了更多功能
-
sh:已经被bash替换
-
nologin:让用户无法登录
bash (/bin/bash)是目前大多数Linux 版本采用的默认shell
shell脚本用途
-
将简单的命令组合完成复杂的工作,自动化执行命令,提高工作效率
-
减少手工命令的重复输入,一定程度上避免人为错误
-
将软件或应用的安装及配置实现标准化
-
用于实现日常性的,重复性的运维工作,如:文件打包压缩备份,监控系统运行状态并实现告警等
脚本执行逻辑及执行方式
-
顺序执行:程序按从上到下顺序执行
-
选择执行:程序执行过程中,根据条件的不同,进行选择不同分支继续执行
-
循环执行:程序执行过程中需要重复执行多次某段语句
常用命令
tr
格式
tr [选项]... SET1 [SET2]
-d 删除
-s 压缩
-c 用字符串1中字符集的补集替换此字符集,要求字符集为ASCII。
重定向
类型 | 设备文件 | 文件描述编号 | 默认设备 |
---|---|---|---|
标准输入 | /dev/stdin | 0 | 键盘 |
标准输出 | /dev/stdout | 1 | 显示器 |
标准错误输出 | /dev/stderr | 2 | 显示器 |
下面进行具体举例
[root@net /]# ls /data /xxx 2>&1 1> /data/all.log
ls: 无法访问/xxx: 没有那个文件或目录
[root@net /]# cat /data/all.log
/data:
all.log
这条命令将标准错误输出重定向到标准输出,然后将标准输出重定向到 /data/all.log 文件。
[root@net /]# ls /data /xxx 1>&2 2> /data/all.log
/data:
all.log
这里将标准输出重定向到标准错误输出,然后将标准错误输出重定向到 /data/all.log 文件。
[root@net /]# cat /data/all.log
ls: 无法访问/xxx: 没有那个文件或目录
[root@net /]# ls /data /xxx 1>/data/all.log 2> /data/all.log
[root@net /]# cat /data/all.log
/data:
all.log
®/xxx: 没有那个文件或目录
此处一个一个的写
[root@net /]# ls /data /xxx 2>/data/all.log 1> /data/all.log
[root@net /]# cat /data/all.log
/data:
all.log
®/xxx: 没有那个文件或目录
此处发现改变顺序并不会影响文件里面内容的顺序
[root@net /]# ls /data /xxx &>/data/all.log 1> /data/all.log
[root@net /]# cat /data/all.log
/data:
all.log
®/xxx: 没有那个文件或目录
此处可知并不会被覆盖
[root@net /]# ls /data /xxx 1>/data/all.log &> /data/all.log
[root@net /]# cat /data/all.log
ls: 无法访问/xxx: 没有那个文件或目录
/data:
all.log
同上
管道符
将左侧的命令输出结果,作为右侧命令的输入(处理对象)可以 叠加使用
举例:echo "123123" |passwd --stdin root
变量
变量范围
-
区分大小写
-
不能使程序中的保留字和内置变量:如:if, for,hostname 命令 a=
-
只能使用数字、字母及下划线,且不能以数字开头,注意:不支持短横线 “ - ”,和主机名相反
-
不要使用内置的变量,使用英文尽量使用词义通俗易懂,PATH
-
大驼峰 StudentFirstName
-
小驼峰 studentFirstName
-
下划线 student_name
read -p
变量作用范围
通过export abc来定义全局变量使得其在全局生效
整数的运算
注意算中要添加空格不然不会被识别:
当然也可以用其他方式计算:
Linux中也可以用计算器来计算
通过对随机数取余来实现规定范围内的随机数:
如图表示一个1到20的随机数:
环境变量
-
由系统提前创建,用来设置用户的工作环境
-
可以使用env查看环境变量
-
需要记住的常用环境变量
通过使用命令env来查看:
其中
$USER 表示用户名称
$HOME 表示用户的宿主目录
$LANG 表示语言和字符集
$PWD 表示当前所在工作目录
$PATH 表示可执行用户程序的默认路径
位置变量
预定义(状态)变量
-
$*:表示所有位置参数的内容看成一个整体返回 返回所有
-
$@:表示所有位置参数的内容分割成n份,每份作为一个独立的个体返回 返回所有
-
$?:表示前一条命令执行后的返回状态,返回值为 0 表示执行正确,返回任何非 0值均表示执行出现异常
-
$#:表示命令行中位置参数的总个数
-
$0:表示当前执行的脚本或程序的名称 当前脚本的名字
-
$$:当前bash的进程id
-
$!: 后台任务最后一个id
` ` $( ) 调用命令执行的结果
' ' 强引用 不识别变量 本来含义
" " 弱引用 他识别变量
{ } 规定变量的范围
命名要求
条件语句
测试
操作符:
-d:测试是否为目录(Directory)
-e:测试目录或文件是否存在(Exist)
-a:测试目录或文件是否存在(Exist)
-f:测试是否为文件(File)
-r:测试当前用户是否有权限读取(Read)
-w:测试当前用户是否有权限写入(Write)
-x:测试当前用户是否有权限执行(eXcute)
-L: 测试是否为软连接文件
测试是文件还是文件夹:
比较整数数值
等于
大于:
小于
字符串比较
[ 字符串1 = 字符串2 ] 是否相同
[ 字符串1 != 字符串2 ] 是否不相同
[ -z 字符串 ] 是否为空
[ -n 字符串 ] 字符是否存在
逻辑测试(短路运算)
且
第一个要真 第二 个也要真 才能是真
如果第一个为假 ,整个 就为假 不用执行下个操作
cmd1 && cmd2
或
一 真即为真
如果第一个 为真 那么 不用执行第二个
第一个为假 ,才需要执行第二个
cmd1 || cmd2
实际效果大抵如下:
双中括号
[[ expression ]] 用法
== 左侧字符串是否和右侧的PATTERN相同
注意:此表达式用于[[ ]]中,PATTERN为通配符
=~ 左侧字符串是否能够被右侧的正则表达式的PATTERN所匹配
注意: 此表达式用于[[ ]]中;扩展的正则表达式
() {}
(CMD1;CMD2;...)和 { CMD1;CMD2;...; } 都可以将多个命令组合在一起,批量执行
区别在于()不会改变系统环境而{}会改变()相当于又开了一个bash环境
if语句的结构
分支结构
单分支
if 判断条件; then 条件为真的分支代码 fi
双分支
if 判断条件; then 条件为真的分支代码 else 条件为假的分支代码 fi
多分支
if 判断条件1 then 条件1为真的分支代码 elif 判断条件2 then 条件2为真的分支代码 elif 判断条件3;then 条件3为真的分支代码 else 以上条件都为假的分支代码 托底 fi
case
case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac read -p i case $i in PAT1) 分支1 ;; PAT2) 分支2 ;; ... *) 默认分支 ;; 格式
循环语句
for
列表循环
for 变量名 in {list} do command done
不带列表循环
for 变量名 do command done
类似于C语言风格的for循环
for ((expr1;expr2;expr3)) do command done
while
while
当命令判断为假时停止
格式:
while :
do
done
双重循环及跳出循环
-
break跳出单个循环 break n 数字数字是几代表跳出n层循环
-
continue终止某次循环中的命令,但是不会完全终止命令
-
exit 直接退出脚本
until
until 循环与 while 循环类似,while 循环能实现的脚本 until 同样也可以实现,但区别是while 循环在条件为真是继续执行循环,而 until 则是在条件为假时执行循环
until 循环语句的语法结构如下所示。
until 条件测试操作 do 命令序列 done
正则表达式
元字符(字符匹配)
. | 匹配任意单个字符,可以是一个汉字 |
[] | 匹配指定范围内的任意单个字符,示例:[zhou] [0-9] [] [a-zA-Z] [[:alpha:]] [0-9a-zA-Z]= |
[:alnum:] | [^] 匹配指定范围外的任意单个字符,示例:[^zhou] [^a.z] [a.z] |
[:alnum:] | 字母和数字 |
[:alpha:] | 代表任何英文大小写字符,亦即 A-Z, a-z |
[:lower:] | 小写字母,示例:[[:lower:]],相当于[a-z] |
[:upper:] | 大写字母 |
[:blank:] | 空白字符(空格和制表符) |
[:space:] | 包括空格、制表符 (水平和垂直)、换行符、回车符等各种类型的空白,比[:blank:]包含的范围广 |
[:cntrl:] | 不可打印的控制字符(退格、删除、警铃...) |
[:digit:] | 十进制数字 |
[:xdigit:] | 十六进制数字 |
[:graph:] | 可打印的非空白字符 |
[:print:] | 可打印字符 |
[:punct:] | 标点符号 |
\w | #匹配单词构成部分,等价于[_[:alnum:]] |
\W | #匹配非单词构成部分,等价于[^_[:alnum:]] |
\S | #匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。 |
\s | #匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意Unicode 正则表达式会匹配全角空格符 |
注意1-29指的是1-2和9 匹配框得写第一个
r..t 表示r和t直接有两个字
基础正则表达一些特殊的符号需要加\转译故而我们常用扩展正则
表示次数
* | #匹配前面的字符任意次,包括0次,贪婪模式:尽可能长的匹配 |
.* | #任意长度的任意字符 不包括0次 |
\? | #匹配其前面的字符出现0次或1次,即:可有可无 |
\+ | #匹配其前面的字符出现最少1次,即:肯定有且 >=1 次 |
\{n\} | #匹配前面的字符n次 |
\{m,n\} | #匹配前面的字符至少m次,至多n次 |
\{,n\} | #匹配前面的字符至多n次,<=n |
\{n,\} | #匹配前面的字符至少n |
ifconfig ens33 | grep netmask|grep -o
位置锚定
^ #行首锚定, 用于模式的最左侧
$ #行尾锚定,用于模式的最右侧
^PATTERN$ #用于模式匹配整行 (单独一行 只有root)
^$ #空行
^[[:space:]]*$ # 空白行 tab 换行 回车
分组或其他
分组:( ) 将多个字符捆绑在一起,当作一个整体处理,如:(root)+
后向引用:分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名
方式为: \1, \2, \3, ...
\1 表示从左侧起第一个左括号以及与之匹配右括号之间的模式所匹配到的字符
扩展正则表达式
表示次数
* 匹配前面字符任意次
? 0或1次
+ 1次或多次
{n} 匹配n次
{m,n} 至少m,至多n次
{,n} #匹配前面的字符至多n次,<=n,n可以为0
{n,} #匹配前面的字符至少n次,<=n,n可以为0表示分组
表示分组
() 分组
分组:() 将多个字符捆绑在一起,当作一个整体处理,如:\(root\)+
后向引用:\1, \2, ...
| 或者
a|b #a或b
C|cat #C或cat
(C|c)at #Cat或cat
grep
grep [选项]… 查找条件 目标文件
选项:
-color=auto #对匹配到的文本着色显示
-m # 匹配#次后停止 匹配到 #行停止
grep -m 1 root /etc/passwd #多个匹配只取第一个
-v 显示不被pattern匹配到的行,即取反
grep -Ev '^[[:space:]]*#|^$' /etc/fstab
-i 忽略字符大小写
-n 显示匹配的行号
-c 统计匹配的行数
grep -c root /etc/passwd #统计匹配到的行数
-o 仅显示匹配到的字符串
-q 静默模式,不输出任何信息 写脚本
-A # after, 后#行
grep -A3 root /etc/passwd #匹配到的行后3行业显示出来
-B # before, 前#行
-C # context, 前后各#行
-e 实现多个选项间的逻辑or关系,如:grep –e ‘cat ' -e ‘dog' file
grep -e root -e bash /etc/passwd #包含root或者包含bash 的行
grep -E root|bash /etc/passwd
-w 匹配整个单词
grep -w root /etc/passwd
useradd rooter
-E 使用ERE,相当于egrep
-F 不支持正则表达式,相当于fgrep
-f file 根据模式文件,处理两个文件相同内容 把第一个文件作为匹配条件 grep -f a b
-r 递归目录,但不处理软链接 开始搜索目录
-R 递归目录,但处理软链接
sed
sed [选项]... {脚本(如果没有其他脚本)} [输入文件]...
基本用法
sed [option]... 'script;script;...' [input file...] 选项 自身脚本语法 支持标准输入管道常用选项:
-n 不输出模式空间内容到屏幕,即不自动打印
-e 多点编辑[root@www data]#sed -n -e '/^r/p' -e'/^b/p' /etc/passwd
-f FILE 从指定文件中读取编辑脚本
-r, -E 使用扩展正则表达式
-i.bak 备份文件并原处编辑
sed -r 基础正则#说明:
-ir 不支持
-i -r 支持
-ri 支持
-ni 会清空文件
sed会自动打印如果不加-n,p指的是打印模式空间里面的故而这样写会打印两遍
这样写即可
sed脚本格式
1. 不给地址:对全文进行处理(比如行号)
2. 单地址:
3. 地址范围:
#,# #从#行到第#行,3,6 从第3行到第6行
#,+# #从#行到+#行,3,+4 表示从3行到第7行
当然也可以取反
4. 步进:~
1~2 奇数行
2~2 偶数行
当然也可以这么写
搜索替代
s/pattern/string/修饰符 查找替换,支持使用其它分隔符,可以是其它形式:s@@@,s###
替换修饰符:
g 行内全局替换
p 显示替换成功的行
w /PATH/FILE 将替换成功的行保存至文件中
I,i 忽略大小写
面试题
用命令行更改config.txt文件,把里面所有的“name”更改为“address”
sed -i 's/name/address/g' config.txt写出查询file.txt以abc结尾的行
sed -n '/abc$/p' file.txt查看linux服务器ip的命令,同时只显示包含ip所在的行打印出来
提取版本号
也可以:
sed的高级用法
P 打印模式空间开端至\n内容,并追加到默认输出之前
h 把模式空间中的内容覆盖至保持空间中
H 把模式空间中的内容追加至保持空间中
g 从保持空间取出数据覆盖至模式空间
G 从保持空间取出内容追加至模式空间
x 把模式空间中的内容与保持空间中的内容进行互换
n 读取匹配到的行的下一行覆盖至模式空间
N 读取匹配到的行的下一行追加至模式空间
d 删除模式空间中的行
D 如果模式空间包含换行符,则删除直到第一个换行符的模式空间中的文本,并不会读取新的输入行,而使
用合成的模式空间重新启动循环。如果模式空间不包含换行符,则会像发出d命令那样启动正常的新循环
甚至空格都不影响使用
AWK
awk:Aho, Weinberger, Kernighan,报告生成器,格式化文本输出,GNU/Linux发布的AWK目前由自由软件基金会(FSF)进行开发和维护,通常也称它为 GNU AWK
有多种版本:
AWK:原先来源于 AT & T 实验室的的AWK
NAWK:New awk,AT & T 实验室的AWK的升级版
GAWK:即GNU AWK。所有的GNU/Linux发布版都自带GAWK,它与AWK和NAWK完全兼容GNU AWK 用户手册文档
gawk:模式扫描和处理语言,可以实现下面功能
vim: 是将整个文件加载到内存中 再进行编辑, 受限你的内存
awk(语言): 读取一行处理一行,
在 Linux/UNIX 系统中,awk 是一个功能强大的编辑工具,逐行读取输入文本,默认以空格或tab键作为分隔符作为分隔,并按模式或者条件执行编辑命令。而awk比较倾向于将一行分成多个字段然后进行处理。AWK信息的读入也是逐行
指定的匹配模式进行查找,对符合条件的内容进行格式化输出或者过滤处理,可以在无交互
的情况下实现相当复杂的文本操作,被广泛应用于 Shell 脚本,完成各种自动化配置任务。
工作原理:
前面提到 sed 命令常用于一整行的处理,而 awk 比较倾向于将一行分成多个“字段”然后再进行处理,且默认情况下字段的分隔符为空格或 tab 键。awk 执行结果可以通过 print 的功能将字段数据打印显示。
格式:
awk [options] 'program' var=value file…说明:
program通常是被放在单引号中,并可以由三种部分组成
BEGIN语句块
模式匹配的通用语句块
END语句块
常见选项:
-F “分隔符” 指明输入时用到的字段分隔符,默认的分隔符是若干个连续空白符
-v var=value 变量赋值
第一步:执行BEGIN{action;… }语句块中的语句
第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,
从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
第三步:当读至输入流末尾时,执行END{action;…}语句块
BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中
END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块
pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块
基础用法
awk 'patterm{action}'
awk的语法
awk [选项] '模式{处理动作}' ##一定要用单引号
常见用法:
提取磁盘的利用率:
提取用户名和uid号
提取ip地址
或者
常见的内置变量
FS | 指定每行文本的字段分隔符,缺省默认为空格或制表符(tab)。与 “-F”作用相同 -v "FS=:" |
OFS | 输出时的分隔符 |
NF | 当前处理的行的字段个数 |
NR | 当前处理的行的行号(序数) |
$0 | 当前处理的行的整行内容 |
$n | 当前处理行的第n个字段(第n列) |
FILENAME | 被处理的文件名 |
RS | 行分隔符。awk从文件上读取资料时,将根据RS的定义就把资料切割成许多条记录,而awk一次仅读入一条记录进行处理。预设值是\n |
FS的用法:
OFS的用法:
RS的用法 :
NF的用法:
NR的用法
条件判断
0表示不打印1表示打印
打印$3小于10的情况
awk中的for循环
数组
awk数组特性:
-
awk的数组是关联数组(即key/value方式的hash数据结构),索引下标可为数值(甚至是负数、小数等),也可为字符串 1. 在内部,awk数组的索引全都是字符串,即使是数值索引在使用时内部也会转换成字符串 2. awk的数组元素的顺序和元素插入时的顺序很可能是不相同的
-
awk数组支持数组的数组