linux shell 脚本

Shell

基础知识

什么是 shell ?

在计算机科学中,shell 就是一个命令解释器

功能定位

shell 担任了操作系统和应用程序之间的中间人,它负责将应用程序的输入命令信息解释给操作系统,操作系统将指令集结果反馈给应用程序。

Category

linux: sh/csh/ksh/bash/…

Basic Operation

  1. 查看当前系统的 shell
1
echo $SHELL
  1. 查看当前系统环境支持的 shell
1
cat /etc/shells
  1. 更改默认的 shell
1
chsh 用户名 -s newshell

执行操作

shell脚本的执行通常可以采用以下几种方式:

1
2
3
bash /path/to/script-name 或 /bin/bash /path/to/script-name (强烈推荐使用)
/path/to/script-name 或 ./script-name (当前路径下执行脚本)
source script-name 或 . script-name (注意“

Shell 变量

Category

变量 说明
本地变量 变量仅仅在当前Shell终端有效
环境变量 也叫全局变量,变量在当前Shell终端其派生出来的任意子进程Shell终端中有效
内置变量 Shell解析器内部的一些功能参数变量

本地变量

def: 变量仅仅在当前 Shell 终端有效

表现样式

① 普通变量的定义方式有如下三种:

类型 样式 特点 备注
无引号 变量名=变量值 变量值必须是一个整体,中间没有特殊字符 “=” 前后不能有空格
单引号 变量名=’变量值’ 原字符输出
双引号 变量名=”变量值” 变量值先解析,后整合

② 命令变量的定义方式有如下两种:

类型 样式 特点 备注
反引号 变量名=‘ 命令’ 反引号 不要用中文
小括号 变量名=$(命令) $()

环境变量

def:也叫全局变量,变量在当前Shell终端其派生出来的任意子进程Shell终端中有效

表现形式:

1
export 变量=值

变量操作

查看:$变量名、“$变量名”、${变量名}、”${变量名}”

取消:unset 变量名

内置变量

属性含义

符号 意义
$0 获取当前脚本文件名
$n 获取脚本的第n个参数值,样式:$1,${1}
$# 获取脚本参数的总个数
$? 获取上一个指令的状态返回值(0为成功,非0为失败)

条件表达式

语法格式

① 方式A:test 条件表达式

1
2
3
4
5
# 注意:=号两边必须有空格
test 1 = 1
echo $?
test 1 = 2
echo $?

② 方式B:[ 条件表达式 ]

1
2
3
4
5
# 注:=号两边必须有空格,并且方括号[、]与条件表达式之间也要至少有一个空格
[ 1 = 1 ]
echo $?
[ 1 = 2 ]
echo $?

条件成立,状态返回值是0;条件不成立,状态返回值是1。

表达样式

① 重点表达式

逻辑 样式 特点
&& 命令1 && 命令2 只有1成功,2才执行
|| 命令1 || 命令2 1和2只能执行一个
文件 样式 特点
-f|d|s -f file_name 判断文件格式
-r|w|x -x file_name 判断文件权限

② 一般表达式

数字 样式 特点
eq 数字1 eq 数字2 相等eq,不等ne
gt 数字1 gt 数字2 gt大于,小于lt
字符串 样式 特点
== | != str1 == str2 字符串内容是否一致
-z|n -z str1 z空,n不空

③ 计算表达式

样式一:$[计算表达式]、a=$[变量名a+1]

样式二:$((计算表达式)) 或 a=$((变量名a+1))

样式三:let 变量名a=变量名a+1

注意:样式三的表达式必须是一个整体,中间不能出现空格等特殊字符

常见符号

① 信息传递

重定向符号 特点
>|< 表示将符号左侧|右侧的内容,以覆盖的方式输入到右侧|左侧文件
>>|<< 表示将符号左侧|右侧的内容,以追加的方式输入到右侧|左侧文件的末尾行中

② 其他符号

后台展示符号 特点
& 就是将一个命令从前台转到后台执行
信息获取符号 特点
1 表示正确输出的信息
2 表示错误输出的信息
2>&1 代表所有输出的信息,也可以简写为 “&>”

常见命令

grep

global search regular expression and print out the line

文本搜索命令

命令格式

1
grep [参数] [关键字] <文件名>

参数详解

参数 说明
-c 只输出匹配行的计数
-n 显示匹配行及行号
-v 显示不包含匹配文本的所有行
-E 使用扩展正则匹配

sed

行文件编辑工具

命令格式

1
sed [参数] '<匹配条件> [动作]' [文件名]

参数详解

参数 说明
参数为空 表示sed的操作效果,实际上不对文件进行编辑
-n 默认只输出修改的内容,一般在动作中结合”p”使用
-i 表示对文件进行编辑

注:mac版本的bash中使用 -i参数,必须在后面单独加个东西: -i ‘’

① 替换操作

命令格式

1
2
3
sed -i '行号s#原内容#替换后内容#列号' [文件名]

sed -i '/匹配关键字/s#原内容#替换后内容#列号' [文件名]

注意:行号不写表示所有行,列号不写表示第1列,列号写成g,表示当前所有匹配的内容

awk

awk是一个功能非常强大的文档编辑工具,它不仅能以行为单位还能以列为单位处理文件。

命令格式

1
awk [参数] 'BEGIN{...}{动作}END{...}' [文件名]
常见参数 说明
-F 指定列的分隔符
常见动作 说明
print 显示内容
$0 显示当前行所有内容
$n 显示当前行的第n列内容,如果存在多个$n,它们之间使用逗号(,)隔开
常见内置变量 说明
FILENAME 当前输入文件的文件名,该变量是只读的
NF 输出最后一列的内容
OFS 输出格式的列分隔符,缺省是空格
FS 输入文件的列分融符,缺省是连续的空格和Tab

流程

if 语句

① 单分支if

特点:单条件,单结果

1
2
3
4
if [ 条件 ]
then
指令
fi

示例:

1
2
3
4
5
6
#! /bin/bash
# 单if语句的使用场景
if [ "$1" == "man" ]
then
echo "您的性别是:男"
fi

② 双分支if

特点:单条件,两结果

1
2
3
4
5
6
if [ 条件 ]
then
指令1
else
指令2
fi

示例:

1
2
3
4
5
6
7
8
#! /bin/bash
# 双分支if语句的使用场景
if [ "$1" == "man" ]
then
echo "您的性别是:男"
else
echo "您的性别是:女"
fi

③ 多分支if

特点:n条件,n+1结果

1
2
3
4
5
6
7
8
9
if [ 条件1 ]
then
指令1
elif [ 条件2 ]
then
指令2
else
指令3
fi

示例:

1
2
3
4
5
6
7
8
9
10
11
#! /bin/bash
# 多分支if语句的使用场景
if [ "$1" == "man" ]
then
echo "您的性别是:男"
elif [ "$1" == "woman" ]
then
echo "您的性别是:女"
else
echo "您的性别,我不知道"
fi

1.2 脚本案例

① 需求说明

要求脚本执行需要有参数,通过传入参数来实现不同的功能。

参数和功能详情如下:

参数 执行效果
start 服务启动中…
stop 服务关闭中…
restart 服务重启中…
* 脚本x.sh使用方式为: x.sh [ start|stop|restart ]

② 脚本内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#! /bin/bash
# 多if语句的使用场景
if [ "$1" == "start" ]
then
echo "服务启动中..."
elif [ "$1" == "stop" ]
then
echo "服务关闭中..."
elif [ "$1" == "restart" ]
then
echo "服务重启中..."
else
echo "$0 脚本的使用方式: $0 [ start | stop | restart ]"
fi

2. case语句

我们发现多if语句使用的时候,代码量很多,而且整体看起来确实有那么一丁点乱,有没有办法更好的实现这种效 果呢?就是case语句。

2.1 语法格式

1
2
3
4
5
6
7
8
9
case 变量名 in
值 1)
指令1
;;
...
值 n)
指令n
;;
esac

注:
① 首行关键字是case,末行关键字esac
② 选择项后面都有 )
③ 每个选择的执行语句结尾都有两个分号

2.2 语法示例

场景:在多if语句的基础上对脚本进行升级

需求:要求脚本执行需要有参数,通过传入参数来实现不同的功能

参数和功能详情如下:

参数 执行效果
start 服务启动中…
stop 服务关闭中…
restart 服务重启中…
* 脚本x.sh使用方式为: x.sh [ start|stop|restart ]

脚本内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# vi case.sh 
#! /bin/bash
# case语句使用场景
case "$1" in
"start")
echo "服务启动中..."
;;
"stop")
echo "服务关闭中..."
;;
"restart")
echo "服务重启中..."
;;
*)
echo "$0 脚本的使用方式: $0 [ start | stop | restart ]"
;;
esac

3. 循环语句

3.1 语法格式

for循环语句

1
2
3
4
for 条件
do
执行语句
done

注:for语句,循环的数量有列表中元素个数来决定

简单实践:

1
2
3
4
5
6
#! /bin/bash
# for语句的使用示例
for i in $(ls /root)
do
echo "${i}"
done

while条件

1
2
3
4
while 条件
do
执行语句
done

注:while语句,只要条件满足,就一直循环下去

简单实践:

1
2
3
4
5
6
7
8
#! /bin/bash
# while 的示例
a=1
while [ "${a}" -lt 5 ]
do
echo "${a}"
a=$((a+1))
done

util条件

1
2
3
4
until 条件
do
执行语句
done

注:until语句,只要条件不满足,就一直循环下去

简单实践:

1
2
3
4
5
6
7
8
#! /bin/bash
# until的示例
a=1
until [ "${a}" -eq 5 ]
do
echo "${a}"
a=$((a+1))
done

shell 函数

1. 函数定义

定义:函数就是将某些命令组合起来实现某一特殊功能的方式,是脚本编写中非常重要的一部分。

1.1 基本语法

简单函数格式

1
2
3
function 函数名(){
函数体
}

调用函数:函数名

传参函数格式

1
2
3
function 函数名(){
函数体 $n
}

调用函数:函数名 参数

注:function 关键字可以省略

1.2 简单实践

简单函数定义和调用示例

1
2
3
4
5
6
7
#! /bin/bash
# 函数使用场景一:执行频繁的命令
func(){
echo "my name is smart"
}
# 函数调用
func

函数传参和函数体内调用参数示例

1
2
3
4
5
6
7
#! /bin/bash
# 函数的使用场景二
func(){
echo "my name is $1"
}
# 函数调用
func "smart"

2. 函数进阶

2.1 进阶样式

脚本传参和函数调用

1
2
# 脚本传参数
/bin/bash 脚本名 参数

函数定义和调用:

1
2
3
4
函数名(){
函数体 $1
}
函数名 $1

函数定义和调用(生成用):

1
2
3
4
5
本地变量名="$1"
函数名(){
函数体 $1
}
函数名 "${本地变量名}"

2.2 进阶实践

脚本传参+函数调用:

1
2
3
4
5
6
7
#! /bin/bash
# 函数传参演示
func(){
echo "my name is $1"
}
# 函数传参
func $1

脚本传参+函数调用(生产用):

1
2
3
4
5
6
7
#! /bin/bash
# 函数的使用场景二
name="$1"
func(){
echo "my name is $1"
}
func "${name}"
-------------THANKS FOR READING-------------