目录
一、概述
1. 简介
- Shell是一个命令解释器,用于接受应用程序或用户的命令,调用操作系统内核。
- 与此同时,Shell也可以认为是一种编程语言,其内容可以由linux命令组成。
2. 入门
- Shell文件可以以 .sh 结尾,也可以不写;
- Shell文件一般在第一行写#!/bin/bash,用于指定shell脚本的解析器;
- shell脚本的执行方式:
- 可以使用sh或bash命令执行文件;
- 赋予shell文件执行权限,然后直接使用shell文件执行;
[root@docker data]# ll
总用量 4
-rw-r--r--. 1 root root 33 4月 16 23:13 ex.sh
[root@docker data]#
[root@docker data]# ll
总用量 4
-rw-r--r--. 1 root root 33 4月 16 23:13 ex.sh
[root@docker data]# cat ex.sh
#!/bin/bash
echo "This is test"
[root@docker data]# sh ex.sh
This is test
[root@docker data]# bash ex.sh
This is test
[root@docker data]# chmod 744 ex.sh
[root@docker data]# ll
总用量 4
-rwxr--r--. 1 root root 33 4月 16 23:13 ex.sh
[root@docker data]# ./ex.sh
This is test
[root@docker data]# pwd
/root/data
[root@docker data]# /root/data/ex.sh
This is test
[root@docker data]#
3. Shell解析器
- Linux中包含很多Shell解析器,如下所示:
- CentOS中默认的解析器是bash,而sh其实是bash的软连接:
二、变量
1. 系统变量
// 家目录
[root@docker data]# echo $HOME
/root
// 当前目录
[root@docker data]# echo $PWD
/root/data
// 默认是Shell解析器
[root@docker data]# echo $SHELL
/bin/bash
// 当前用户
[root@docker data]# echo $USER
root
2. 特殊变量
$n | n为数字,其中$0便是脚本名称,$1~9表示对应变量,如果n大于10则需写成$[10] | |
$# | 表示参数个数 | |
$* | 表示所有参数,当以""括起来时,代表所有参数整体,一个变量 | |
$@ | 表示所有参数,当以""括起来时,还是代表每个参数 | |
$? | 返回命令执行的结果,执行成功或输出结果为True,则$?结果为0,否则为其他数字 | |
$$ | 脚本运行时的pid |
3. 自定义变量
(1)定义与撤销变量
- shell中变量默认为字符型
- 变量的种类:
- 静态:k="v"或k='v'或k=v
- 动态:k=`v` : v是变量 v系统自带的命令
- 引用方式:$变量名或${变量名}
【注意:=左右不能有空格】
[root@docker data]# a=1
[root@docker data]# echo $a
1
// 撤销变量
[root@docker data]# unset a
[root@docker data]# echo $a
[root@docker data]#
(2)声明只读变量(静态)
[root@docker data]# readonly a=2
[root@docker data]# echo $a
2
// 只读变量无法被撤销,重启主机后将失效
[root@docker data]# unset a
-bash: unset: a: 无法反设定: 只读 variable
// 如果参数值包含空格则需要使用引号
[root@docker data]# b="1 2 3"
[root@docker data]# echo $b
1 2 3
//参数默认都是字符型,无法直接进行数值运算
[root@docker data]# c=2
[root@docker data]# echo $a+$c
2+2
(3)数组
语法格式:arr=(v1 v2 ... vn) //数组用()表示且元素使用空格分隔
[root@docker data]# vim arr.sh
[root@docker data]# cat arr.sh
#/bin/bash
arr=(1 2 3 4)
echo "所有元素 : ${arr[@]}"
echo "第一个元素 : ${arr[0]}"
echo "元素个数 : ${#arr[@]}"
[root@docker data]# bash arr.sh
所有元素 : 1 2 3 4
第一个元素 : 1
元素个数 : 4
三、运算符
1. 语法
(1)表达式区域
- $((运算式))
- $[运算式]
- expr 运算式【注意:此方式数值及符号间需要有空格】
(2)运算符
- + , - , \*, /, % // 加,减,乘,除,取余
2. 实例
// expr 加法
[root@docker data]# expr 1 + 2
3
// expr 乘法 注意*前需要加\
[root@docker data]# expr 2 \* 2
4
// 混合运算 注意需要使用`
[root@docker data]# expr `expr 2 \* 2` + 1
5
// $(()) 方式 注意需要写echo
[root@docker data]# echo $((2*2+1))
5
// $[] 方式 注意需要写echo
[root@docker data]# echo $[2*2+1]
5
四、条件判断
1. 语法
[条件] :条件只要非空结果即为true,否则为false;
【注意:条件前后需要有空格】
[root@docker data]# [ ]
[root@docker data]# echo $?
1
[root@docker data]# [ s ]
[root@docker data]# echo $?
0
2. 判断符号
= | 字符串比较 |
整数比较 | |
-lt | 小于 |
-le | 小于等于 |
-gt | 大于 |
-ge | 大于等于 |
-eq | 等于 |
-ne | 不等于 |
文件权限判断 | |
-r | 有读权限 |
-x | 有执行权限 |
-w | 有写权限 |
文件类型判断 | |
-f | 文件存在是一个常规文件 |
-e | 文件存在 |
-d | 文件存在是一个文件夹 |
[root@docker data]# ll
总用量 12
-rwxrwxrwx. 1 root root 33 4月 16 23:29 aa.sh
-rw-r--r--. 1 root root 132 4月 17 00:43 arr.sh
-rw-r--r--. 1 root root 132 4月 16 23:49 test1.sh
[root@docker data]# [ -f aa.sh ]
[root@docker data]# echo $?
0
[root@docker data]# [ 2 -gt 3 ]
[root@docker data]# echo $?
1
五、流程控制
1. if 与 case
(1)if
[root@docker data]# vim if.sh
[root@docker data]# cat if.sh
#/bin/bash
if [ $1 -eq 1 ];then
echo "该值等于1"
elif [ $1 -eq 2 ]
then
echo "该值等于2"
fi
[root@docker data]# bash if.sh 1
该值等于1
[root@docker data]# bash if.sh 2
该值等于2
注意:
- [] 内条件前后需要有空格;
- then如果写在if后面需要写分号,换行则不用;
- 最后结尾需要写fi;
(2)case
该语法类似于switch
[root@docker data]# vim case.sh
[root@docker data]# cat case.sh
#/bin/bash
case $1 in
1)
echo "这个值是1"
;;
2)
echo "这个值是2"
;;
*)
echo "这个值不是1或2"
;;
esac
[root@docker data]# sh case.sh 1
这个值是1
[root@docker data]# sh case.sh 2
这个值是2
[root@docker data]# sh case.sh 3
这个值不是1或2
注意:
- 条件后需要写in;
- 匹配条件后需要写);
- 每个业务语句后需要些 ;; 终止case
- 最后结尾需要写esac;
2. for 与 while
(1)for
[root@docker data]# vim for.sh
[root@docker data]# cat for.sh
#!/bin/bash
s=0
for((i=0;i<=100;i++))
do
s=$[$s+$i]
done
echo $s
[root@docker data]# sh for.sh
5050
// 另一种for循环,直接遍历数组
[root@docker data]# vim for2.sh
[root@docker data]# cat for2.sh
#!/bin/bash
for i in $*
do
echo "参数: $i"
done
for i in $@
do
echo "参数: $i"
done
for i in "$*"
do
echo "参数: $i"
done
for i in "$@"
do
echo "参数: $i"
done
[root@docker data]# sh for2.sh 1 2 3 4 5
参数: 1
参数: 2
参数: 3
参数: 4
参数: 5
// 注意上面五条结果与下面五条结果分别使用$*、$@实现
参数: 1
参数: 2
参数: 3
参数: 4
参数: 5
参数: 1 2 3 4 5
// 此处为两这区别,$*将所有参数变为一个变量而$@仍为多个变量
参数: 1
参数: 2
参数: 3
参数: 4
参数: 5
(2)while
[root@docker data]# vim while.sh
[root@docker data]# cat while.sh
#!/bin/bash
s=0
i=1
while [ $i -le 100 ]
do
s=$[$s+$i]
i=$[$i+1]
done
echo $s
[root@docker data]# sh while.sh
5050
3. 括号问题
条件表达式 不能用 < >
while for 能用 < > 不能用 -gt
[] =》 条件判断
() => 数值运算
七、函数
1. 系统函数
(1)basename获取文件的名称
[root@docker data]# basename /root/data/aa.sh
aa.sh
[root@docker data]# basename /root/data/aa.sh .sh
aa
(2)dirname获取文件的路径
[root@docker data]# dirname /root/data/aa.sh
/root/data
2. 自定义函数
(1)语法
[ function ] funName[()]
{
content;
[return int;]
}
funName
// 方括号部分都为可选部分
(2)实例
[root@docker data]# vim fun.sh
[root@docker data]# cat fun.sh
#!/bin/bash
function sum()
{
s=0
s=$[ $1 + $2 ]
echo "$s"
}
read s1;
read s2;
sum $s1 $s2
[root@docker data]# sh fun.sh
1
2
3
*六、Shell工具
1. cut
剪切文件每行的字符串,可以指定分隔符,分割后可以输出指定列,类似于split;
选项 | ||
-d | 指定分隔符 | cut -d "分隔符" file |
-f | 指定输出的对应列 | cut -d "分隔符" -f 1 file // 输出第一列 |
[root@docker data]# cat 1.log
aa bb
aaa bbb
cc bb
dd dd
aa cc
// 1、以空格分隔1.log并输入第一列
[root@docker data]# cut -d " " -f 1 1.log
aa
aaa
cc
dd
aa
// 2、输出aaa
[root@docker data]# cat 1.log | grep aaa
aaa bbb
[root@docker data]# cat 1.log | grep aaa | cut -d " " -f 1
aaa
2. sed
可以实现文本替换、文本插入、删除某行,但需要注意并非直接改变源文件,只是将想要的结果打印出来,当然,也可以存到文件中。
选项及命令 | |
-e | 用于衔接指令 |
a | 在指定行后插入一行 |
d | 删除包含某内容的行 |
s | 查找某个词并替换 |
g | 全局 |
// 文件1.log
[root@docker data]# cat 1.log
aa bb
aaa bbb
cc bb
dd dd
aa cc
// 在包含aaa的一行下插入ee
[root@docker data]# sed "/aaa/a ee" 1.log
aa bb
aaa bbb
ee
cc bb
dd dd
aa cc
// 在第二行下方插入一行ee
[root@docker data]# sed "2a ee" 1.log
aa bb
aaa bbb
ee
cc bb
dd dd
aa cc
// 删除包含aaa的行
[root@docker data]# sed "/aaa/d" 1.log
aa bb
cc bb
dd dd
aa cc
// 将文件中aa替换为ee
[root@docker data]# sed "s/aa/ee/" 1.log
ee bb
eea bbb
cc bb
dd dd
ee cc
// 先将文件中aa替换为ee,再删除eea 此处时-e的使用
[root@docker data]# sed -e "s/aa/ee/" -e "/eea/d" 1.log
ee bb
cc bb
dd dd
ee cc
3. awk
切割文件,如果匹配到指定格式的内容指定设定的动作,默认空格分隔。
选项 | |
-F | 指定分隔符 |
-v | 赋值一个用户定义变量 |
内置变量 | |
FILENAME | 文件名 |
NR | 已读的行数 |
NF | 切割后列的个数 |
[root@docker data]# vim 2.log
[root@docker data]# cat 2.log
aa:bb
aaa: :bbb
cc:bb
dd:a:dd
aa:cc:ee
// 输出以aa开头的行的第二列
[root@docker data]# awk -F : '/^aa/{print $2}' 2.log
bb
cc
// 在整个输出的前后加内容
[root@docker data]# awk -F : 'BEGIN{print "begin"} /^aa/{print $2} END{print "end"}' 2.log
begin
bb
cc
end
// 自定义变量
[root@docker data]# awk -F : -v i=1 '/^aa/{print $2""i}' 2.log
bb1
1
cc1
// 输出文件名、当前行、所有行数
[root@docker data]# awk -F : -v i=1 '{print "fileName:"FILENAME "nowLine:"NR "colNum:" NF}' 2.log
fileName:2.lognowLine:1colNum:2
fileName:2.lognowLine:2colNum:3
fileName:2.lognowLine:3colNum:2
fileName:2.lognowLine:4colNum:3
fileName:2.lognowLine:5colNum:0
fileName:2.lognowLine:6colNum:3
[root@docker data]# cat 2.log
aa:bb
aaa: :bbb
cc:bb
dd:a:dd
aa:cc:ee
// 查找第几行为空行 其中/^$/为正则
[root@docker data]# awk '/^$/{print NR}' 2.log
5
4. sort
对文件内容排序
选项 | |
-n | 数值大小排序 |
-r | 倒序 |
-t | 设置分隔字符 |
-k | 指定排序的列 |
[root@docker data]# cat 3.log
1:2:33
10:22:1
33:21:34
14:33:11
22:12:34
// 以:为分隔符 以数值倒序对第2列排序
[root@docker data]# sort -t : -nrk 2 3.log
14:33:11
10:22:1
33:21:34
22:12:34
1:2:33