Shell概述
Shell
是一个命令行解释器,它接收应用程序/用户命令,然后调用操作系统内核。
此外,Shell
还是一个功能相当强大的编程语言,易编写、易调试、灵活性强。
Shell脚本入门
Linux提供的Shell解释器
Linux
中提供的所有的解释器有:
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
/bin/tcsh
/bin/csh
使用以下命令查看所有解释器:
1 | cat /etc/shells |
其中:/bin/sh
其实就是指向/bin/bash
的一个链接。
使用以下命令可以验证。
1 | cd /bin && ll | grep bash |
并且在Centos
中默认的解释器为bash
,使用以下命令查看。
1 | echo $SHELL |
Shell脚本指定解释器
在Shell
脚本的第一行中输入#!/bin/bash
指定解释器。
为了保存所有的Shell
脚本,我们在家目录下创建一个shell_learn
文件夹。
1 | cd && mkdir shell_learn |
写下来进入shell_learn
使用vim
编写第一个Shell脚本
。
1 | cd ~/shell_learn && vim helloworld.sh |
编写以下代码指定解释器为#!/bin/bash
。
1 |
|
脚本的执行
脚本的执行一般有两种方式:
bash/sh
+脚本的相对路径或绝对路径- 采用脚本的相对路径或绝对路径
bash/sh+脚本的相对路径或绝对路径
这种情况下不要求脚本必须有执行权限。
相对路径
1
sh helloworld.sh
绝对路径
1
sh ~/shell_learn/helloworld.sh
bash
结果同理,不再演示。
采用脚本的相对路径或绝对路径
这种情况下必须要求脚本具有执行权限没有权限,直接运行会报错。
赋予执行权限后,运行没有问题。
1 | chmod +x helloworld.sh |
第一种执行方法,本质是bash解析器帮你执行脚本,所以脚本本身不需要执行权限。
第二种执行方法,本质是脚本需要自己执行,所以需要执行权限。
变量
系统变量
在Linux
操作系统中有很多已经定义好的系统变量,这些变量的内容一般都是具有实际意义的,不允许修改其内容,如果强行修改后可能会导致系统错误。
常见系统变量(一般使用大写字母)如下所示:
1 | $HOME、$PWD、$SHELL、$USER、$PATH |
查看系统变量的值:
1 | echo $HOME $PWD $SHELL $USER $PATH |
自定义变量
基本语法
定义变量:变量名=变量值
注意:=前后不能有空格。
撤销变量:
unset
变量名声明静态变量:
readonly
变量注意:静态变量无法撤销。
变量定义规则
- 变量名称可以由字母、数字和下划线组成,但是不能以数字开头,环境变量名建议大写。
- 等号两侧不能有空格
- 在
bash
中,变量默认类型都是字符串类型,无法直接进行数值运算。 - 变量的值如果有空格,需要使用双引号或单引号括起来。
变量的获取
变量在获取时使用$
+变量名。
案例实操
定义变量
A
,然后获取其值。1
2A=5
echo $A给
A
重新赋值,并获取新值。1
2A=100
echo $A撤销变量
A
1
2unset A
echo $A声明静态变量
B=520
,并演示其无法撤销。1
2
3readonly B=520
echo $B
unset B在
bash
中,变量默认类型都是字符串类型,无法直接进行数值运算1
2C=1+2
echo $C变量的值如果有空格,需要使用双引号或单引号括起来。
1
2
3D=I am a teacher.
D="I am a teacher."
echo $D可以把变量提升为全局变量,可供其他Shell程序使用。
修改
helloworld.sh
,在最后一行加上echo $A
。先定义
A=100
,然后运行helloworld.sh
脚本1
2A=100
./helloworld.sh此时
helloworld.sh
脚本中的A
打印出来为空值。接下来将变量
A
提升为全局环境变量,然后再运行helloworld.sh
脚本。1
2export A
./helloworld.sh这个时候打印的结果就没有问题了。
特殊变量
$#
功能描述:获取所有输入参数个数,常用于循环,判断参数的个数是否正确以及加强脚本的健壮性。
例如创建脚本params.sh
1 | cd ~/shell_learn |
并添加以下内容。
1 | !/bin/bash |
运行脚本
1 | bash params.sh a b c d |
$n
功能描述:n
为数字,$0
代表该脚本名称,$1-$9
代表第一到第九个参数,十以上的参数,十以上的参数需要用大括号包含,如${10}
。
修改params.sh
内容如下:
1 |
|
运行脚本
1 | bash params.sh a b c d |
$*,$@
功能描述:
$*
:这个变量代表命令行中所有的参数,$*
把所有的参数看成一个整体。$@
:这个变量也代表命令行中所有的参数,不过$@
把每个参数区分对待。
修改params.sh
内容如下:
1 |
|
运行脚本
1 | bash params.sh a b c d |
$?
功能描述:最后一次执行的命令的返回状态。如果这个变量的值为0
,证明上一个命令正确执行;如果这个变量的值为非0
(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了。
执行脚本params.sh
。
1 | bash params.sh a b c d |
查看该脚本是否执行正确
1 | echo $? |
运算符
前面我们给大家演示过,在Shell
中所有的内容都被当作字符串处理,所以无法进行数值计算,有的时候我们确实是需要使用到数学计算,这个时候该如何操作。
这个时候就需要使用到运算符:$[运算式]
或$((运算式))
1 | C=$[1+2] |
条件判断表达式
基本语法
格式:[ condition ]
注意:
condition
前后都要有空格,并且也遵循非空即为true
。
常用判断条件
整数比较
命令 | 意义 |
---|---|
-eq |
(equal)等于 |
-ne |
(not equal)不等于 |
-lt |
(less then)小于 |
-le |
(less equal)小于等于 |
-gt |
(greater than)大于 |
-ge |
(greater equal)大于等于 |
案例:判断22
是否大于等于27
.
1 | [ 22 -ge 27 ] |
返回0表示true
,返回1表示false
。
文件权限判断
-r
:有读的权限(read
)-w
:有写的权限(write
)-x
:有执行的权限(execute
)
案例:判断params.sh
文件是否有执行的权限。
1 | [ -x params.sh ] |
文件类型判断
-e
:文件存在(existence
)-f
:文件存在并且是一个常规文件(file
)-d
:文件存在并且是一个目录(directory
)
案例:判断helloworld.sh
是否存在且是一个常规文件。
1 | [ -f helloworld.sh ] |
多条件判断
- 且操作:
&&
。表示前一条命令执行成功时,才执行后一条命令。 - 或操作:
||
。表示上一条命令执行失败后,才执行下一条命令。
1 | [ 100 -gt 99 ] && echo yes || echo no |
程序控制流(重点)
if语句
基本语法
单分支
1
2
3
4if [ 条件判断表达式 ]
then
...程序...
fi双分支
1
2
3
4
5
6if [ 条件判断表达式 ]
then
...程序1...
else
...程序2...
fi多分支
1
2
3
4
5
6
7
8
9if [ 条件判断表达式1 ]
then
...程序1...
elif [ 条件判断表达式2 ]
then
...程序2...
else
...程序3...
fi
案例实操
定义一个shell
脚本,名称叫if.sh
,功能为输入一个数字判断该数字与100
之间的大小关系,如果比100
大返回大于100
,如果输入的是100
返回等于100
,如果比100
小返回小于100
。
1 |
|
case语句
基本语法
1 | case $变量名 in |
注意:
case
行尾必须为单词in
,每一个模式匹配必须以右括号)
结束。- 双分号
;;
表示命令序列结束,相当于java
中的break
。- 最后的
*)
表示默认模式,相当于java
中的default
。
案例实操
创建一个case.sh
脚本,功能为输入一个数字,如果是1
输出True
,如果输入0
输出False
,输入其他内容输出None
。
1 |
|
for循环
基本语法1
1 | for ((初始值;循环控制条件;变量变化)) |
案例实操1
编写一个for1.sh
脚本,功能为从1加到100。
1 |
|
基本语法2
1 | for 变量 in 值1,值2,值3... |
案例实操2
编写一个for2.sh
脚本,该脚本功能为返回所有的输入参数。
1 |
|
while循环
基本语法
1 | while [ 条件判断表达式 ] |
案例实操
编写一个while.sh
脚本,功能为从1
加到100
。
1 | !/bin/bash |
read读取控制台输入
基本语法
1 | read (选项) (参数) |
选项
-p
:指定读取值时的提示符;-t
:指定读取时等待的时间(单位:秒),默认为一直等待。参数
变量:指定读取值的变量名
案例实操
编写一个脚本read.sh
,功能为提示7秒内,读取控制台输入的内容。
1 |
|
7
秒内如果输入内容则直接将该内容返回,如果没有输入则中断程序。
函数
系统函数
basename
1 | basename [string/pashname] [suffx] |
返回路径中的文件名,或者文件夹名称(最后一层)。如果是文件路径则返回该文件名称;如果是文件夹路径则返回文件夹名称。
1 | basename /home/hadoop100/桌面/1.txt |
指定suffx
参数,则在文件名称中将指定的文件后缀去掉。
1 | basename /home/hadoop100/桌面/1.txt .txt |
dirname
1 | dirname [path] |
返回文件的绝对路径。
1 | dirname /home/hadoop100/桌面/1.txt |
自定义函数
基本语法
1 | [function] funname [()] |
案例实操
定义一个脚本fun.sh
,脚本中定义一个函数sum
,其功能是求所有数之和。
1 | !/bin/bash |
Shell工具(重点)
cut
cut
的工作就是“剪”,具体的说就是在文件中负责剪切数据用的。cut
命令从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段输出。
基本用法
1 | cut [选项参数] filename |
选项参数说明
-f
:列号,提取第几列。-d
:分隔符,按照指定分隔符分隔列,默认是制表符\t
。
案例实操
首先创建数据
1 | vim cut.txt |
写入以下内容:
1 | zhagnsan 99 |
切割
cut.txt
第一列。1
cut -d " " -f 1 cut.txt
将
wangwu
从文件中切割出来。1
cat cut.txt|grep wangwu|cut -d " " -f 1
将系统变量
$PATH
按照:
进行切分,获取第2
个:
后面的所有内容1
echo $PATH|cut -d ":" -f 3-
切割
ifconfig
打印出来的ip
地址1
ifconfig ens33|grep netmask|cut -d 'i' -f 2|cut -d ' ' -f 2
awk
一个强大的文本分析工具,把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行分析处理。
基本用法
1 | awk [选项参数] '/pattern1/{action1} /pattern2/{action2}...' filename |
选项参数
-F
:指定输入文件的分隔符。-v
:赋值一个用户定义变量。
案例实操
数据准备,将/etc/passwd
文件拷贝到当前文件夹。
1 | cp /etc/passwd . |
passwd数据的含义:
用户名:密码(加密过后的):用户id:组id:注释:用户家目录:shell解析器
搜索
passwd
文件以root
关键词开头的所有行,并输入改行的第7列。1
awk -F ":" '/^root/{print $7}' passwd
搜索
passwd
文件以root
关键字开头的所有行,并输出该行的第1
列和第7
列,中间以,
号分割1
awk -F ":" '/^root/{print $1","$7}' passwd
只显示
passwd
文件的的第一列和第七列,以逗号分割,且在所有行前面添加列名user
,shell
在最后一行添加minglog,/bin/zushuai
。1
awk -F ":" 'BEGIN{print "user, shell"} {print $1","$7} END{print "minglog,/bin/zuishuai"}' passwd
注意:
BEGIN
在所有数据读取之前执行;END
在所有数据执行之后执行。将
passwd
文件中的用户id
增加数值1
并输出1
awk -v i=1 -F ":" '{print $3+i}' passwd
awk的内置变量
变量 | 说明 |
---|---|
FILENAME |
文件名 |
NR |
已读的记录数(行号) |
NF |
浏览记录的域的个数(切割后,列的个数) |
案例实操
统计
passwd
文件名,每行的行号,每行的列数1
awk -F ":" '{print "filename:"FILENAME",linenum:"NR",col:"NF}' passwd
查询
ifconfig
命令输出结果中的空行所在的行号1
ifconfig | awk '/^$/{print NR}'
切割
IP
1
ifconfig ens33 | grep netmask | awk -F ' ' '{print $2}'
正则表达式操作
在Linux
中大量的命令都支持正则表达式操作,例如:grep
,sed
,awk
等等。所以能够有效正则表达式结合相关命令进行使用,会大大提高工作效率。
正则表达式操作见正则表达式。