一.Shell介绍:shell是一个命令行解释器,脚本语言,活动在应用程序与内核之间,用于接收应用程序(用户)命令,调用操作系统内核。
(1)编译型语言:
程序在执行之前需要个专门的编译过程,把程序编译成为机器语言文件,运行时不需要重新翻译,直接使用编译的结果就行了。程序执行效率高,依养编译器,跨平台性差些。如C、C++、java
(2)解释型语言:
程序不需要编译,程序在运行时由解释器翻译成机器语言,每执行一次都要翻译一次。因此效率比较低。比如Python/javaScript/Shell等都是解释型语言。
二、Shell解析器
(1)Linux提供的Shell解析器有:
/bin/sh | 是bash的一个快捷方式 |
/bin/bash | bash是大多数Linux默认的shell,包含的功能几乎可以涵盖shell所有的功能 |
/sbin/nologin | 表示非交互,不能登录操作系统 |
/bin/dash | 小巧,高效,功能相比少一些 |
/bin/tcsh | 具有C语言风格的一种shell,具有许多特性,但是也有一些缺陷 |
/bin/csh | 是csh的增强版本,完全兼容csh |
(2)bash和sh的关系:
[root@Linux01 bin]# ll | grep bash
-rwxr-xr-x. 1 root root 942200 3月 23 2017 bash
lrwxrwxrwx. 1 root root 4 6月 29 19:35 sh -> bash
(3)Centos默认的解析器是bash
[root@Linux01 bin]# echo $SHELL
/bin/bash
三、Shell脚本入门
一句话概括:简单来说脚本就是将需要执行的命令保存到文本中,按照顺序执行(由上往下执行),它是解释型的,不需要编译。
1.脚本格式
脚本以#!/bin/bash或者#!/bin/env bash开头(指定解析器)
脚本中间写注释信息内容,单行注释# 多行注释 :<<EOF EOF 注释内容如下:
<<EOF
name:second-shell.sh
desc:创建文件,在文件中添加内容,打印信息
update:2020-07-02
path:/home
EOF
然后写脚本内容
2.第一个Shell脚本:输出helloworld
(1)需求:创建一个Shell脚本,输出helloworld
(2)案例实操:
[jinghang@hadoop101 datas]$ touch helloworld.sh
[jinghang@hadoop101 datas]$ vi helloworld.sh
在helloworld.sh中输入如下内容
#!/bin/bash
echo "helloworld"
运行脚本,会输出 helloWord
3、脚本的常用执行方式
第一种:
采用bash或sh+脚本的相对路径或绝对路径(不用赋予脚本+x权限)
sh+脚本的相对路径
[jinghang@hadoop101 datas]$ sh helloworld.sh
Helloworld
sh+脚本的绝对路径
[jinghang@hadoop101 datas]$ sh /home/jinghang/datas/helloworld.sh
helloworld
bash+脚本的相对路径
[jinghang@hadoop101 datas]$ bash helloworld.sh
Helloworld
bash+脚本的绝对路径
[jinghang@hadoop101 datas]$ bash /home/jinghang/datas/helloworld.sh
Helloworld
第二种:
采用输入脚本的绝对路径或相对路径执行脚本(必须具有可执行权限+x,推荐采用这种方式)
(a)首先要赋予helloworld.sh 脚本的+x权限
[jinghang@hadoop101 datas]$ chmod +x helloworld.sh
(b)执行脚本
相对路径
[jinghang@hadoop101 datas]$ ./helloworld.sh
Helloworld
绝对路径
[jinghang@hadoop101 datas]$ /home/jinghang/datas/helloworld.sh
Helloworld
注意:第一种执行方法,本质是bash解析器帮你执行脚本,所以脚本本身不需要执行权限。第二种执行方法,本质是脚本需要自己执行,所以需要执行权限。
4、查看脚本的执行流程(一般使用这个命令来查看脚本执行的步骤)
[jinghang@hadoop101 datas]$ bash -x batch.sh
5、查看脚本的语法(一般使用这个命令来检查脚本语法错误)
[jinghang@hadoop101 datas]$ bash -n batch.sh
4、shell变量:变量是用来临时保存数据的,该数据是可以变化的数据
- 读取Shell中所有变量命令:set 读取环境变量:env
-
系统变量
a)$HOME、$PWD、$SHELL、$USER
b)读取变量:echo $变量名 -
自定义变量
a)用户变量
作用域(只在当前会话的当前用户下有效)
定义变量:
变量名=值
变量名=`执行命令`
变量名=$(执行命令)
读取变量:echo $变量名
echo ${A:2:3} (切片,读取变量几位,索引从0开始,第一个冒号后面代表索引开始位置,第二个冒号后面代表读取几位)
echo ${A}
echo $A
撤销变量:unset 变量名
静态变量(一旦创建,只可读,不能unset): readonly 变量名=值
定义有类型的变量
目的:给变量做一些限制,固定变量的类型
语法:declare 选项 变量名=变量值
常用选项
-i 将变量看作整数
-r 创建只读变量
b)全局环境变量
作用域(针对于当前会话下的所有用户有效)
关键字:export
定义变量:export 变量名=值
撤销和读取同上
c)系统环境变量
作用域(针对于所有会话下的所有用户都有效)
编辑配置文件:vim /etc/profile
例如添加系统环境变量 MYNAME=jinghang
#系统环境变量
export MYNAME=jinghang
变量生效:source /etc/profile
经验技巧:
(1)变量名称可以由字母、数字和下划线组成,但是不能以数字开头,环境变量名建议大写。
(2)等号两侧不能有空格
(3)在bash中,变量默认类型都是字符串类型,无法直接进行数值运算。
(4)变量的值如果有空格,需要使用双引号或单引号括起来。 - 特殊变量
a)$n
语法:$n (功能描述:n为数字,$0代表该脚本名称,$1-$9代表第一到第九个参数,十以上的参数,十以上的参数需要用大括号包含,如${10})
b)$#
语法:$# (功能描述:获取所有输入参数个数,常用于循环)
c)$*
语法:$* (功能描述:这个变量代表命令行中所有的参数,$*把所有的参数看成一个整体)
d)$@
语法:$@ (功能描述:这个变量也代表命令行中所有的参数,不过$@把每个参数区分对待)
e)$?
语法:$? (功能描述:最后一次执行命令的返回状态。如果值为0,命令正确执行;如果值为非0(具体是哪个数,由命令自己来决定),则命令执行不正确)
5、shell数组
- 定义:
Shell 数组用括号来表示,元素用"空格"符号分割开,如果元素中包含空格,则该元素使用双引号引起来,例如"hello word"
- 语法:
往数组里添加值,数组的长度自增,元素索引从0开始
数组名=(value1 value2 value3)
- 赋值:
创建时添加 数组名=(A B "C B" D)
创建后添加 数组名[4]=E
- 修改:
局部:根据索引修改数组 例如:数组名[0]=F
整体:可以直接给数组变量重新赋值
- 读取:
获取数组中所有的元素:echo ${数组名[*]} 或者 echo ${数组名[@]}
根据索引读取数组元素:echo ${数组名[索引值]}
获取数组的长度:echo ${#数组名[*]} 或者 echo ${#数组名[@]}
- 删除:
unset 关键字来删除数组元素,格式如下:
unset 数组名[index]
不写下标,删除整个数组,格式如下:
unset 数组名
6、Shell中的运算符
- 整数运算语法(默认):
(1)$(( 运算式 )) 或 $[运算式]
(2)运算符 + , - , *, /, % 加,减,乘,除,取余
(3)运算式要与小扩号之间有空格,中括号的话不用加空格
(4)expr + , - , \*, /, % 加,减,乘,除,取余 注意:expr表达式运算符间要有空格 例如 expr $A + $B
- 小数运算:
bc:Linux下的一个计算器程序,可以处理整数和小数。Shell 本身只支持整数运算,想计算小数就得使用 bc 这个外部的计算器
在 Shell 脚本中,借助管道或者输入重定向来使用 bc 计算器。
语法:echo "scale=要保留的小数位数 ; 计算式" | bc
expression就是希望计算的数学表达式
案例1:计算3*8/7 结果保留4位小数
echo "scale=4; 3*8/7" | bc
案例2:计算3*8/7 ,再乘5,结果保留3位小数
echo "scale=3; 3*8/7*5" | bc
案例4:计算4/9,保留2位,结果赋值给ret变量
ret=$(echo "scale=2;4/9" | bc)
7、Shell条件判断
- 语法:
注意:条件非空即为true,[ 判断式 ]返回true,[判断式] 返回false。[ 判断式 ](注意判断式前后要有空格)
- 常用条件判断
(1)两个整数之间比较
= 字符串比较
-lt 小于(less than)
-le 小于等于(less equal)
-eq 等于(equal)
-gt 大于(greater than)
-ge 大于等于(greater equal)
-ne 不等于(Not equal)
(2)按照文件权限进行判断
-r 有读的权限(read)
-w 有写的权限(write)
-x 有执行的权限(execute)
(3)按照文件类型进行判断
-f 文件存在并且是一个常规的文件(file)
-e 文件存在(existence)
-d 文件存在并是一个目录(判断目录)(directory)
- 案例:
多条件判断(&& 表示前一条命令执行成功时,才执行后一条命令,|| 表示上一条命令执行失败后,才执行下一条命令)
[jinghang@hadoop101 ~]$ [ condition ] && echo OK || echo NOTOK
OK
[jinghang@hadoop101 ~]$ [ condition ] && [ ] || echo NOTOK
NOTOK
8、Shell流程控制
- if 判断语句
注意事项:
(1)[ 条件判断式 ],中括号和条件判断式之间必须有空格
(2)if后要有空格
语法1:
if [ 条件判断式 ]
then
主体代码
fi
语法2:
if [ 条件判断式 ]
then
主体代码
else
主体代码
fi
语法3:
if [ 条件判断式 ]
then
主体代码
elif [条件判断式]
then
主体代码
else
主体代码
fi
- case 判断语句
基本语法:
case $变量名 in
"值1")
如果变量的值等于值1,则执行程序1
;;
"值2")
如果变量的值等于值2,则执行程序2
;;
…省略其他分支…
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac
注意事项:
1)case行尾必须为单词“in”,每一个模式匹配必须以右括号“)”结束。
2)双分号“;;”表示命令序列结束,相当于java中的break。
3)最后的“*)”表示默认模式,相当于java中的default。
- for 循环语句
基本语法:
语法一
for (( 初始值;循环控制条件;变量变化 ))
do
逻辑代码
done
语法二
$* : 读取传入脚本中的全部参数,把参数看作一个整体
$@ : 读取传入脚本中的全部参数,把参数区分对待
for 变量 in "$*或者$@"
do
逻辑代码
done
注意:for 与 ( 号之间要有空格
- while 循环语句
基本语法
while [ 条件判断式 ]
do
逻辑代码
done
注意:While 与 [ 号之间要有空格
9、read读取控制台输入
- 基本语法:read 【选项】【参数】
选项
-p 指定读取值时的提示符;
-t 指定读取值时等待的时间(秒);
参数:指定读取值的变量名
- 案例
1、请在3秒内输入用户名
[root@Linux01 home]# read -p "请在3秒内输入用户名:" -t 3 name
请在3秒内输入用户名:zhangsan
2、通过read定制菜单栏
cat <<-EOF
1:代表对数据进行倒序排列
2:代表对数据进行正序排列
EOF
read -p "请在20秒内输入数字:" -t 20 num
10、Shell函数
- 系统函数
basename
basename 命令会删掉所有的前缀包括最后一个(‘/’)字符,然后将字符串显示出来(去掉路径,只显示最后的文件名)
例如:[root@Linux01 home]# basename /home/test/ccc.txt
ccc.txt
dirname
从给定的包含绝对路径的文件名中去除文件名,然后返回剩下的路径(去掉文件名,只显示文件名之前的绝对路径)
例如:[root@Linux01 home]# dirname /home/test/ccc.txt
/home/test
- 自定义函数
语法:
function 函数名()
{
方法体
[return int;]
}
编写完脚本之后,执行脚本,就能调用函数了,直接输函数名就可以(在外部调用);在脚本内部调用函数直接函数名就可以。
经验技巧
(1)必须在调用函数地方之前,先声明函数,shell脚本逐行运行。不会先编译。
(2)函数返回值,只能通过$?系统变量获得,可以显示加:return返回,如果不加,将以最后一条命令运行结果,作为返回值。return后跟数值n(0-255)
创建用户函数(只能当前用户调用)
1.在用户的家目录中(/home/用户名)找到隐藏文件.bashrc进行编写函数
2.source .bashrc
3.现在就能直接调用函数了
创建系统函数(所有用户和会话可调用,重启后仍可调用)
1.root用户在/etc/bashrc文件下编写函数
2、source /etc/bashrc
3.所有用户都可直接调用
11、 shell文本处理工具
- cut(查看)
功能描述:cut的工作就是“剪”,具体的说就是在文件中负责剪切数据用的,cut指令用于显示行中的指定部分,删除文件中的指定字段。
语法:cut 【选项】【文件】
选项
-b <起始字节位置-结束字节位置> 仅显示行中指定字节范围的内容。例如,“-b 2-10”将显示第2~10个字节位置的内容,当只有一个数字时,则仅显示指定字符位置的内容.
-f <起始列位置-结束列位置> 显示指定列的字段内容
-d <分隔符> 指定字段的分隔符,默认的字段分隔符为“TAB”
-c <起始字符位置-结束字符位置> 仅显示行中指定范围的字符。例如,“b2-10” 将显示第2~10个字符位置的内容。当只有一个数字时,则仅显示指定字符位置的内容
案例:
切割ifconfig 后打印的IP地址,显示ip地址前3位
ifconfig eth0 | grep "inet addr" | cut -d : -f 2 | cut -d " " -f 1 | cut -c 1-3
- sort(查看)
功能描述:它将文件进行排序,并将排序结果标准输出
语法:sort 【选项】【参数】
选项
-n 依照数值的大小排序
-r 以相反的顺序来排序
-t 设置排序时所用的分隔字符
-k 指定需要排序的列
参数:是指待排序的文件
案例:
将用户列表按照主ID进行倒序排列
[mayun@Linux01 home]$ sort -t : -nrk 4 /etc/passwd
- 正则表达式
概述:正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE)。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本
单字符匹配
\d 匹配一个数字字符。等价于[0-9]
\D 匹配一个非数字字符。等价于[^0-9]
\w 匹配包括下划线的任何单词字符。类似但不等价于[A-Za-z0-9_]
\W 匹配任何非单词字符。等价于 [^A-Za-z0-9_]
\s 匹配空白字符,包括空格、制表符、换页符等等,等价于[ \f\n\r\t\v]
\S 匹配任何可见字符。等价于[^ \f\n\r\t\v]
.点 匹配除“\n”和"\r"之外的任何单个字符
[a-z] 字符范围,匹配a~z之间的任意字符
[^a-z] 匹配除了a~z之间的其他字符
\n 匹配换行符
多字符匹配
+ 匹配前面的子表达式一次或多次(大于等于1次)
* 匹配前面的子表达式任意次
? 匹配前面的子表达式零次或一次
{n} n是一个非负整数。匹配确定的n次
{n,m} m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次
其他
^ 匹配输入字行首
$ 匹配输入行尾
| 将两个匹配条件进行逻辑“或”(or)运算
x|y 匹配x或y
贪婪模式:贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配 例如: [a-b]*表达式去匹配字符串ababababababbaba,就会全部匹配上
非贪婪模式:在整个表达式匹配成功的前提下,尽可能少的匹配 例如:[a-b]*?表达式去匹配字符串ababababababbaba,就只会匹配ab
- sed
功能描述:sed是一种单行文本流式编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”,接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件结束。文件内容并没有改变,除非你使用重定向存储输出。
语法:sed [选项] ’命令‘ 文件名
选项 功能
-e 直接在指令列模式上进行sed的动作编辑(一次执行多个操作时)。
-i 直接编辑文件(修改源文件)
命令 功能
p 打印一般 -n 配合使用
a 新增,在指定的行之后插入内容
i 新增,在指定的行之前插入内容
d 删除
s 查找并替换 (注意:如果进行全局的查找替换 sed -e 's/查找条件/替换字符串/g' )
案例:
数据准备
(1)将“mei nv”这个单词插入到sed.txt第二行下
sed -e '2a mei nv' sed.txt
(2)删除sed.txt文件所有以wo开头的行
sed -e '/^wo/d' sed.txt
(3)将sed.txt文件中wo替换为ni
sed -e 's/wo/ni/g' sed.txt
注意:‘g’表示global,全部替换
(4)将sed.txt文件中的第二行删除并将wo替换为ni
sed -e '2d' -e 's/wo/ni/g' sed.txt
(5)打开文件注释单行注释的行(删掉第一个#号)
sed -e 's/^#//g' sed.txt
(6) 给文件的前5行内容添加注释
sed -e '1,5s/^/#/g' sed.txt
- awk
功能描述:是一门编程语言,也是一个强大的文本分析工具,逐行扫描文件,默认从第一行到最后一行,寻找匹配特定模式的行,并在这些行上进行你想要的操作。
语法:awk 选项 'pattern1{action1} pattern2{action2}...' 文件名
pattern:表示AWK在数据中查找的内容,就是匹配模式,正则表达式
action:在找到匹配内容时所执行的一系列命令
选项 功能
-F 指定输入文件折分隔符
-v 赋值一个用户定义变量
案例:
(1)搜索passwd文件以root关键字开头的所有行,并输出该行的第7列。
awk -F : '/^root/{print $7}' passwd
(2)搜索passwd文件以root关键字开头的所有行,并输出该行的第1列和第7列,中间以“,”号分割。
awk -F : '/^root/{print $1","$7}' passwd
注意:只有匹配了pattern的行才会执行action
(3)只显示/etc/passwd的第一列和第七列,以逗号分割,且在所有行前面添加列名user,shell在最后一行添加"总用户数:用户数量"。
awk -F : 'BEGIN{sum=0;print "user, shell"} {sum=sum+1;print $1","$7} END{print "总用户为:"sum}' passwd
或者awk -v sum=0 -F : 'BEGIN{print "user, shell"} {sum=sum+1;print $1","$7} END{print "总用户为:"sum}' passwd
注意:BEGIN 在所有数据读取行之前执行;END 在所有数据执行之后执行。
(4)将passwd文件中的用户id增加数值1并输出计算后的用户id和用户名
awk -v i=1 -F : '{print $1 "," $3+i}' passwd
awk的内置变量
变量 说明
FILENAME 文件名
NR 已读的记录数
NF 浏览记录的域的个数(切割后,列的个数)
案例:
(1)统计passwd文件名,每行的行号,每行的列数
awk -F: '{print "filename:" FILENAME ", linenumber:" NR ",columns:" NF}' passwd
(2)切割IP
ifconfig eth0 | grep "inet addr" | awk -F: '{print $2}' | awk -F " " '{print $1}'
(3)查询sed.txt中空行所在的行号
awk '/^$/{print NR}' sed.txt