一、Shell概述
Linux系统的核心是内核。内核控制着计算机系统上的所有硬件和软件,在必要时为应用程序分配硬件, 并根据需要执行程序中的代码。
内核主要负责以下四种功能:
- 系统内存管理
- 软件程序管理
- 硬件设备管理
- 文件系统管理
简单来说Shell是一种特殊的交互式工具,核心是命令提示符,允许输入文本命令,解释命令,并在内核中执行命令。
1.shell的由来
- Linux操作系统的核心是kernal(内核)!
当应用程序在执行时,需要调用计算机硬件的cpu,内存等资源。 - 程序将指令发送给内核执行。
- 为了防止程序发送一些恶意指令导致损坏内核,在内核和应用程序接口之间,设置一个中间层,称为shell!
- 用户编写的程序,经过shell解释给内核,内核执行的结果再由shell返回给程序。shell所支持的命令都是对内核没有威胁,没有损害的。
2.shell是什么
本质上来说:
shell: 一个可以解释shell规定的语法命令的解释器。 解释器负责将应用程序发送的指令,进行检查,合法后交给内核解释执行!返回结果!
shell命令: shell解释器要求的指定语法编写的命令。
shell脚本: 多条shell命令,可以编写在一个文件中,文件中的指令,可以按照顺序执行。将这个文件称为shell脚本!
3.shell中的解释器
使用$SHELL
变量查看当前系统默认的解释器类型
shell支持多种不同风格的解释器,通过/etc/shells
文件查看
Centos默认的解析器是bash
在终端中输入: cat /etc/shells , 等价于/bin/bash -c ‘cat /etc/shells’。 默认/bin/bash必须接一个脚本,作为输入!如果是一条命令,需要加-c (command)
4.linux的环境变量
使用echo $PATH查看linux系统中的环境变量。
本质上来说,我们所执行的命令都是一些文件。如pwd,cd,echo等,它们都在/bin目录下。
之所以它们可以在任何目录下能以 文件名 参数
的形式运行,是应为它们的根目录在环境变量中。
如,我们自己编写一个shell文件,保存在/home/shell目录下
文件内容为
我们在使用source命令的方式运行该脚本文件,发现跳转到了/usr/local目录并显示了该目录下文件内容
但是如果在其他目录中直接以文件名运行,会显示未找到命令。这是应为该
除此之外,还可以用./文件名方式执行该文件。
先给该脚本文件赋上权限,再执行该文件
发现该脚本文件执行成功。
但我们离开该目录,用 文件名的方式执行该文件
发现找不到该命令
我们将该文件复制到某个环境遍历目录下,如/bin目录。
运行该文件,则发现执行成功!
5.第一个shell文件
在/home/shell目录下创建一个文件test01.sh
编辑该文件,内容如下
保存并退出
执行该文件的三种方式
- bash或者sh + 脚本
特点: 新开一个bash执行脚本,一旦脚本执行完毕,bash自动关闭! ./脚本文件
,前提是当前用户对脚本有执行权限,使用当前默认的解释器执行脚本
特点: 新开一个bash执行脚本,一旦脚本执行完毕,bash自动关闭source +脚本 或者 . +脚本
。应为.就是source的缩写
6.脚本的编写要求
- 声明: #!/bin/bash
- 正文: 必须是shell解释器能否解释的命令
7.脚本的执行
- bash 或 sh + 脚本 。
特点: 新开一个bash执行脚本,一旦脚本执行完毕,bash自动关闭! - ./脚本,前提是当前用户对脚本有执行权限,使用当前默认的解释器执行脚本
特点: 新开一个bash执行脚本,一旦脚本执行完毕,bash自动关闭! - source 或 . +脚本 使用当前默认的解释器执行脚本,并不要求当前用户对脚本有执行权限
特点: 在当前bash执行脚本
二、变量操作
1.变量的增删改查
增: 变量名=变量值 (注意:=号的左边和右边不能有空格且区分大小写)
删:unset 变量名
改:变量名=变量值 (注意:=号的左边和右边不能有空格且区分大小写)
查:echo $变量名 set 查看当前定义的所有的变量
定义一个变量a=1,查看该变量
把变量a的值修改为2并打印
查看所有的变量 set
删除变量a的值
2.特殊关键字
- readonly : 用来修饰一个只读(不能修改,删除)变量!
- export: 导出!将一个变量提升为全局变量!
- 局部变量: 默认变量只在定义变量的bash中有效!
如果希望在bash-a访问bash-b中定义的变量!
要求:①bash-b不能关闭
②让bash-b将变量提升为全局变量,才能访问到!
3.变量的生命周期
变量的生命周期:
- 在第一次新增时产生
- 变量在执行unset时,撤销,失效!
- 关闭当前bash,所有定义的变量也不会存在!
重新连接后,该变量消失
注意:
- 变量赋值时,值全部以字符串存在,无法进行运算
- 赋值的值中有空格,需要使用引号引起来。单引号:不能识别$等特殊字符。双引号:可以使用 $字符
``的作用是将引号中的命令执行的结果赋值给变量
`命令` 等价于 $(命令)
4.特殊变量
- $? :上一条命令的返回值。在bash中,若返回值为0,代表上一条命令执行成功。
- $# :参数个数
- $* :参数列表
- $@ :参数列表
- $0脚本名
- $1~n :第n个参数。获取第10个以上的参数时要使用 ${n}
5.运算符
[1]基本语法
(1)“$((运算式))” 或 “$[运算式]”
(2) expr + , - , \*, /, % 加,减,乘,除,取余
注意:expr运算符间要有空格;
*号需要转义为 \*,否则会被视为通配符;
运算指的都是整数的运算,浮点运算需要借助其他的命令!
[2]案例
- 计算3+2的值
[atguigu@hadoop101 datas]# expr 2 + 3
5
- 计算3-2的值
[atguigu@hadoop101 datas]# expr 3 - 2
1
- 计算(2+3)X4的值
expr一步完成计算
[atguigu@hadoop101 datas]# expr `expr 2 + 3` \* 4
20
采用$[运算式]方式
[atguigu@hadoop101 datas]# S=$[(2+3)*4]
[atguigu@hadoop101 datas]# echo $S
6.条件判断
[1]基本语法
[ condition ](注意condition前后要有空格)
注意:条件非空即为true,[ atguigu ]返回true ,[] 返回false。在linux中true为0,false为1
[2]常用判断条件
- 两个整数之间比较
= 字符串的比较,判断两个字符串是否相等. = 两侧要有空格
-lt 小于(less than) -le 小于等于(less equal)
-eq 等于(equal) -gt 大于(greater than)
-ge 大于等于(greater equal) -ne 不等于(Not equal)
例:23是否大于等于22
[ 23 -ge 22 ]
echo $?
返回结果为0 即true
- 按照文件权限进行判断
-r 有读的权限(read) -w 有写的权限(write)
-x 有执行的权限(execute)
例:判断test01.sh是否具有写权限
[ -w test01.sh ]
echo $?
返回结果为0 即true
- 按照文件类型进行判断
-f 文件存在并且是一个常规的文件(file)
-e 文件存在(existence) -d 文件存在并是一个目录(directory)
-s 文件存在且不为空 -L 文件存在且是一个链接(link)
例:判断test01.sh是否是常规文件
[ -f test01.sh ]
echo $?
返回结果为0,即为true
多条件判断(&& 表示前一条命令执行成功时,才执行后一条命令,|| 表示上一条命令执行失败后,才执行下一条命令)
三、流程控制
1. if判断
if [ 条件判断式 ]
then
程序
elif 条件判断式
then 程序..
else 程序..
fi
注意:then必须另起一格。如果非要和if [条件判断式]写在一行,则需要在then的左侧加上 ;
例:写一个简单的bash文件,要求:若用户输入的是1,则输出用户输出的是1;用户输入的是2,则输出用户输入的是2;若用户输入的是3,则输出用户输出的是3,若用户输入的是其他字符,则输出用户输入的不是1,2 ,3
# ! bin/bish
#若用户输入的是1,则输出用户输出的是1;用户输入的是2,则输出用户输入的是2;若用户输入的是3,则输出用户输出的是3
if [ $1 -eq 1 ]
then
echo 用户输入的是1
elif [ $1 -eq 2 ]
then
echo 用户输入的是2
elif [ $1 -eq 3 ]
then
echo 用户输入的是3
else
echo 用户输入的不是1,2,3
fi
测试
注意:
- 若使用linux风格的条件判断语句,if、then、等和 [ 条件判断 ]之间必须要有空格。且then要另起一行或者在then的左侧加上 ;
- 若使用C语言风格的条件判断,则无需考虑这些。但C语言风格的判断需要写两个括号,如判断第一个参数是否等于1,if(($1==1))
2.case 语句
基本语法
case $变量名 in
"值1")
如果变量的值等于值1,则执行程序1 ;;
"值2")
如果变量的值等于值2,则执行程序2 ;;
…省略其他分支…
*)
如果变量的值都不是以上的值,则执行此程序 ;;
esac
注意事项:
- case行尾必须为单词“in”,每一个模式匹配必须以右括号“)”结束。
- 双分号“;;”表示命令序列结束,相当于java中的break。最后的“*)”表示默认模式,相当于java中的default
例:输入一个字符串,如果是guest,则输出欢迎游客,如果是admin,则输出欢迎管理员,如果是其它,输出不欢迎
#! /bin/bash/
#判断用户谁让的参数,若为guest,则输出欢迎游客登录,如果是admin,则输出欢迎管理员,如果是其他,则输出不欢迎
case $1 in
guest)
echo 欢迎游客登录 ;;
admin)
echo 欢迎管理员 ;;
*)
echo 不欢迎 ;;
esac
测试结果
3.for循环
基本语法
for (( 初始值;循环控制条件;变量变化 ))
do
程序
done
或
for (( 初始值;循环控制条件;变量变化 )); do 程序; done
例:计算1到100之间的和
#!/bin/bash
#计算1到100之间的和
sum=0
for((i=1;i<=100;i++))
do
sum=$[$sum+$i]
done
echo 1~100之间的和为: $sum
测试结果
4.增强for循环
基本语法
for 变量 in 值1 值2 值3…
do
程序
done
或
for 变量 in 1 2 3; do 程序; done
或
for 变量 in {1..3}; do 程序; done
例1:遍历集合中每个元素的值
#!/bin/bash
#遍历输出集合中每个元素的值
for i in 张三 李四 王五
do
echo $i 是个好人
done
测试结果
例2:遍历用户指定输入的集合
#!/bin/bash
#遍历输出集合中每个元素的值
for i in $*
do
echo $i 是个好人
done
注意: $* 和$@都是获取用户输入的参数列表,但它们有略微的区别。
当脚本文件中的in后面的参数集不加双引号时,它们是没有区别的。但是如果in后面的参数集加了双引号,$*会把参数集作为一条数据,而$@仍会把参数集作为一个集合。
如
#!/bin/bash
#遍历输出集合中每个元素的值
echo '=======$*带引号======'
for i in "$*"
do
echo $i 是个好人
done
echo '=======$@带引号的结果集======'
for i in "$@"
do
echo $i 是个好人
done
5.while循环
1.基本语法
while [ 条件判断式 ]
do
程序
done
或
while((表达式))
do
程序
done
例:计算1到100的和
#! /bin/bash
#计算1到100之间的和
sum=0
i=1
while(($i<=100))
do
sum=$[$i+$sum]
# linux中认为 i++是一个字符串,所以我们不能直接写成i++
# 方式一: i=$[$i+1]
# 方式二: let i++
let i++
done
echo 1到100之间的和为:$sum
6.read(选项)(参数)
read(选项)(参数)
选项:
-p:指定读取值时的提示符;
-t:指定读取值时等待的时间(秒)。
参数
变量:指定读取值的变量名
例:read -p 请输入参数 -t 10 num
表示:提示符为请输入参数,等待时间为10秒,若10秒内未接收到参数则退出。用户输入的参数用num接收。
四、函数
1.系统函数
[1]basename基本语法
basename [string / pathname] [suffix] (功能描述:basename命令会删掉所有的前缀包括最后一个(‘/’)字符,然后将字符串显示出来。
选项:
suffix为后缀,如果suffix被指定了,basename会将pathname或string中的suffix去掉。
例:截取/home/shell/while.sh路径的文件名称
[root@localhost shell]# basename /home/shell/while.sh
while.sh
[root@localhost shell]# basename /home/shell/while.sh .sh
while
[root@localhost shell]#
[2]dirname基本语法
dirname 文件绝对路径(功能描述:从给定的包含绝对路径的文件名中去除文件名(非目录的部分),然后返回剩下的路径(目录的部分))
例:获取 /home/shell/while.sh 文件的路径
[root@localhost shell]# dirname /home/shell/while.sh
/home/shell
2.自定义函数
基本语法
function funname[()]
{
Action;
[return int;]
}
funname
注意:
- 必须在调用函数地方之前,先声明函数,shell脚本是逐行运行。不会像其它语言一样先编译。
- 函数返回值,只能通过$?系统变量获得,可以显示加:return返回,如果不加,将以最后一条命令运行结果,作为返回值。return后跟数值n(0-255)
例:自定义一个执行两个参数的加法操作的函数
#!/bin.bash
#自定义一个执行两个参数的加法操作的函数
function add()
{
result=$[$1+$2]
echo 两数之和为:$result
#如果没有定义return,返回函数中最后一条语句执行的返回值
#return
}
#读取用户输入的参数作为函数的参数
read -p 请输入第一个参数: num1
read -p 请输入第二个参数: num2
add num1 num2
五、shell工具(重点)
1.wc
wc命令用来计算。利用wc指令我们可以计算文件的Byte数、字数或是列数,若不指定文件名称,或是所给予的文件名为“-”,则wc指令会从标准输入设备读取数据。
- 基本语法
wc [选项参数] filename
- 参数说明
选项参数 | 功能 |
---|---|
-l | 统计文件行数 |
-w | 统计文件的单词数 |
-m | 统计文件的字符数 |
-c | 统计文件的字节数 |
例:查看文件test01.sh中的信息
注意:
- wc命令中,是以空格来区分单词的数量。案例中第一行注释没有空格,则认为它是一个单词。
- wc命令不认为空格是字符
2.cut
cut的工作就是“剪”,具体的说就是在文件中负责剪切数据用的。cut 命令从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段输出。
- 基本语法
cut [选项参数] filename
说明:默认分隔符是制表符 - 选项参数说明
选项参数 | 功能 |
---|---|
-f | f为fileds,列号,提取第几列 |
-d | d为Descriptor分隔符,按照指定分隔符分割列 |
例1:以:为间隔,切割PATH环境变量的第一列
例2:以:为间隔,切割PATH环境变量的第二、三列
例3:选取系统PATH变量值,第2个“:”开始后的所有路径:
例4:以:为间隔,切割PATH环境变量的第一到三列,和第五列
3.sed
sed是一种流编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”,接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。
- 基本用法
sed [选项参数] ‘command’ filename
- 选项参数说明
参数选项 | 功能 |
---|---|
-e | 直接在指令列模式上进行sed的动作编辑。 |
- 命令功能描述
命令 | 功能描述 |
---|---|
a | 新增,a的后面可以接字串,在下一行出现 |
d | 删除 |
e | 查找并替换 |
- 数据准备
[root@localhost shell]# touch sed.txt
[root@localhost shell]# vim sed.txt
zhang san
li si
wang wu
w w
zhao liu
tian qi
- 将“ni hao”这个单词插入到sed.txt第二行下,打印
[root@localhost shell]# sed '2a ni hao' sed.txt
zhang san
li si
ni hao
wang wu
w w
zhao liu
tian qi
注意:文件并没有改变。操作的是流值的值
- 删除sed.txt文件第二行
- 删除sed.txt文件最后一行
- 删除sed.txt文件第二行至最后一行
- 将sed.txt文件中w替换为S
注意:‘g’表示global,全部替换,不加g只会替换第一个匹配到的字符。 - 将sed.txt文件中的第二行删除并将w替换为S
4.sort
sort命令是在Linux里非常有用,它将文件进行排序,并将排序结果标准输出。默认情况以第一个字符串的字典顺序来排序.
- 基本语法
sort(选项)(参数)
选项 | 说明 |
---|---|
-n | 依照数值的大小排序 |
-r | 以相反的顺序来排序 |
-t | 设置排序时所用的分隔字符,默认使用TAB |
-k | 指定需要排序的列 |
-u | u为unique的缩写,即如果出现相同的数据,只出现一行 |
参数:指定待排序的文件列表.
准备数据
[root@localhost shell]# touch sort.sh
bb:40:5.4
bd:20:4.2
xz:50:2.3
cls:10:3.5
ss:30:1.6
- 按照“:”分割后的第三列倒序排序。
5. awk
一个强大的文本分析工具,把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行分析处理。
- 基本用法
awk [选项参数] ‘pattern1{action1} pattern2{action2}…’ filename
pattern:表示AWK在数据中查找的内容,就是匹配模式
action:在找到匹配内容时所执行的一系列命令 - 选项参数说明
选项参数 | 功能 |
---|---|
-F | 指定输入文件折分隔符 |
-v | 赋值一个用户定义变量 |
- 案例
数据准备,将/etc/password 拷贝至当前目录下
sudo cp /etc/passwd ./
例1: 搜索passwd文件以root关键字开头的所有行,并输出该行的第7列。
awk -F: '/^root/{print $7}' passwd
结果: /bin/bash
例2:搜索passwd文件以root关键字开头的所有行,并输出该行的第1列和第7列,中间以“,”号分割。
awk -F: '/^root/{print $1","$7}' passwd
返回结果:root,/bin/bash
注意:只有匹配了patter的行才会执行action
例3:只显示/etc/passwd的第一列和第七列,以逗号分割,且在所有行前面添加列名user,shell在最后一行添加"zhangsan,/bin/lisi"
awk -F : 'BEGIN{print "user,shell"}{print $1","$7}END {print "zhangsan,/bin/lisi"}' passwd
结果:
user,shell
root,/bin/bash
bin,/sbin/nologin
。。。
chrony,/sbin/nologin
rabbitmq,/sbin/nologin
zhangsan,/bin/lisi
注意:BEGIN 在所有数据读取行之前执行;END 在所有数据执行之后执行。
例4:将passwd文件中的用户id增加数值1并输出
awk -v i=1 -F: '{print $3+i}' passwd
结果:
1
2
3
4
5
。。。
- awk的内置变量
变量 | 说明 |
---|---|
FILENAME | 文件名 |
NR | 已读的记录数(行号) |
NF | 浏览记录的域的个数(切割后列的个数) |
例1 :统计passwd文件名,每行的行号,每行的列数
awk -F: '{print "filename:" FILENAME",linenumber:"NR",columns:"NF}' passwd
结果:
filename:passwd,linenumber:1,columns:7
filename:passwd,linenumber:2,columns:7
filename:passwd,linenumber:3,columns:7
filename:passwd,linenumber:4,columns:7
例2 切割IP
ifconfig eth0 | grep "inet addr" | awk -F: '{print $2}' | awk -F " " '{print $1}'
例3 查询sed.txt中空行所在的行号
awk '/^$/{print NR}' sed.txt
结果:4
六、面试题
- Linux常用命令有哪些
参考答案:find、df、tar、ps、top、netstat等。(尽量说一些高级命令)
- Linux查看内存、磁盘存储、io 读写、端口占用、进程等命令
1、查看内存:top
2、查看磁盘存储情况:df -h
3、查看磁盘IO读写情况:iotop(需要安装一下:yum install iotop)、iotop -o(直接查看输出比较高的磁盘读写程序)
4、查看端口占用情况:netstat -tunlp | grep 端口号
5、查看进程:ps aux
- 使用Linux命令查询file1中空行所在的行号
awk '/^$/{print NR}' sed.txt
- 有文件chengji.txt内容如下:
张三 40
李四 50
王五 60
使用Linux命令计算第二列的和并输出
cat chengji.txt | awk -F " " '{sum+=$2} END{print sum}'
- Shell脚本里如何检查一个文件是否存在?如果不存在该如何处理?
#!/bin/bash
if [ -f file.txt ]; then
echo "文件存在!"
else
echo "文件不存在!"
fi
- 用shell写一个脚本,对文本中无序的一列数字排序
[root@CentOS6-2 ~]# cat test.txt
9
8
7
6
5
4
3
2
10
1
[root@CentOS6-2 ~]# sort -n test.txt|awk '{a+=$0;print $0}END{print "SUM="a}'
1
2
3
4
5
6
7
8
9
10
SUM=55
- 请用shell脚本写出查找当前文件夹(/home)下所有的文本文件内容中包含有字符”shen”的文件名称
grep -r "shen" /home | cut -d ":" -f 1