目录
介绍
学习 Shell 是为了提高我们自己工作效率,提高产出,让我们在更少的时间完成更多的事情。Shell 几乎是 IT 企业必须使用的运维自动化编程语言,特别是在运维工作中的服务监控、业务快速部署、服务启动停止、数据备份及处理、日志分析等环节里,shell 是不可缺的。
Shell 编程就是对一堆 Linux 命令的逻辑化处理
格式要求
1.脚本以#!/bin/bash开头
2.脚本需要有可执行权限
示例
1.新建文件
touch test.sh
2.添加执行权限
chmod +x test.sh //
使脚本具有执行权限
3.修改文件
使用vim命令修改test.sh文件(vim test.sh),添加内容
#!/bin/bash
#第一个shell小程序,echo 是linux中的输出命令。
echo "hello word!
shell 的第一行比较特殊,一般都会以#!开始来指定使用的 shell 类型
4.编译
运行脚本:./test.sh
变量
shell 编程中一般分为三种变量:
- 我们自己定义的变量(自定义变量): 仅在当前 Shell 实例中有效,其他 Shell 启动的程序不能访问局部变量。
- Linux 已定义的环境变量(环境变量, 例如:
PATH
, HOME
等..., 这类变量我们可以直接使用),使用env
命令可以查看所有的环境变量,而 set 命令既可以查看环境变量也可以查看自定义变量。 - Shell 变量 :Shell 变量是由 Shell 程序设置的特殊变量。Shell 变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了 Shell 的正常运行
环境变量
使用
echo $HOME
查看所有环境变量
env
常见环境变量
PATH 决定了 shell 将到哪些目录中寻找命令或程序
HOME 当前用户主目录
HISTSIZE 历史记录数
LOGNAME 当前用户的登录名
HOSTNAME 指主机的名称
SHELL 当前用户 Shell 类型
LANGUAGE 语言相关的环境变量,多语言可以修改此环境变量
MAIL 当前用户的邮件存放目录
PS1 基本提示符,对于 root 用户是#,对于普通用户是$
自定义变量
命名规则
1.命名只能使用英文字母,数字和下划线,首个字符不能以数字开头,但是可以使用下划线(_)开头。
2.中间不能有空格,可以使用下划线(_)。
3.不能使用标点符号。
4.不能使用 bash 里的关键字(可用 help 命令查看保留关键字)
使用
#!/bin/bash
#自定义变量hello
hello="hello world"
echo $hello
echo "helloworld!"
使用一个定义过的变量,只要在变量名前面加$符号即可
只读变量
使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变
删除变量
unset 命令可以删除变量,变量被删除后不能再次使用。unset 命令不能删除只读变量。
变量作用域
1.局部变量
局部变量在脚本或者命令中定义,仅在当前shell进程中有效
在命令行中定义变量name,创建脚本test.sh并访问变量name,则访问不到
name='test' #在命令行中定义变量name
vim test.sh
echo $name
~
~bash test.sh #命令行执行test.sh
发现脚本里访问不到变量name,应为定义的name是局部变量只在当前终端进程中有效
2.全局变量
在当前shell中任何地方可以使用的变量,且在子shell中也有效。通过命令env可以查看当前shell中的所有全局变量。定义一个全局变量可以使用export命令
export name=test # 定义全局变量name
vim test.sh
echo $name
~
~bash test.sh #命令行执行test.sh
#输出
test
export定义的全局变量是临时的,当关闭执行定义的shell进程后,定义的变量就会被销毁
3.环境变量
所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量
环境变量本质上就是全局变量,只不过它是在启动终端时通过执行初始化脚本预定义的。
启动终端后直接输入env命令显示得所有变量都是环境变量。要定义环境变量可以在一下文件中通过export定义:
~/.bashrc 只对当前用户的终端有效
~/.profile 只对当前用户的终端有效
/etc/bash.bashrc对所有用户的终端有效
字符串
单双引号
字符串可以用单引号,也可以用双引号,也可以不用引号
#!/bin/bash
a = 'A'
b = "B"
echo $a
echo $b
输出:
A
B
特点:
单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
单引号字串中不能出现单独一个的单引号,但可成对出现,作为字符串拼接使用。
双引号里可以有变量 - 双引号里可以出现转义字符
字符串拼接
#!/bin/bash
a = 'A'
b = "B"
c = "$a$b"
echo $c
输出:
AB
获取长度
在上面的基础之上加上echo ${#c}即可:
#!/bin/bash
a = 'abcd'
b = "efgh"
c = "$a$b"
echo $c
echo ${#c}
输出:
abcdefgh
8
字符串提取
字符串的提取,主要是采用切片的方法来获取
#!/bin/bash
a = 'abcd'
b = "efgh"
c = "$a$b"
echo $c
echo ${#c}
echo ${a:1:3}
输出:
abcdefgh
8
bcd
基本运算符
Shell 编程支持下面5种运算符:
1.算数运算符
2.关系运算符
3.布尔运算符
4.字符串运算符
5.文件测试运算符
算数运算符
#!/bin/bash
a=6;b=3;
val=`expr $a + $b`
val1=`expr $a - $b`
val2=`expr $a \* $b`
val3=`expr $a / $b`
val4=`expr $a % $b`
echo $val
echo $val1
echo $val2
echo $val3
echo $val4
关系运算符
关系运算符只支持数字,不支持字符串,除非字符串的值是数字
#!/bin/bash
score=90;
maxscore=100;
if [ $score -eq $maxscore ]
then
echo "A"
else
echo "B"
fi输出结果:
B
逻辑运算符
#!/bin/bash
a=$(( 1 && 0))
echo $a;输出结果:
0
逻辑与运算只有相与的两边都是1,与的结果才是1;否则与的结果是0
布尔运算符
字符串运算符
#!/bin/bash
a="abc";
b="efg";
if [ $a = $b ]
then
echo "a 等于 b"
else
echo "a 不等于 b"
fi输出:
a 不等于 b
文件测试运算符
比如我们定义好了一个文件路径file="/usr/learnshell/test.sh"
如果我们想判断这个文件是否可读,可以这样if [ -r $file ]
如果想判断这个文件是否可写,可以这样-w $file
流程控制
在任何一门编程语言中都离不开流程控制语句,使用流程控制语句可以帮助程序处理各类复杂的操作,常用的流程控制语句,比如: if-else,while,for循环等,在linux 的shell 编程语法中,也提供了丰富的流程控制语句
if
if分为单分支结构、双分支结构和多分枝结构。
单分支结构
语法结构:
if 条件
then 命令
fi
#!/bin/bash
a="abc";
b="efg";
if [ $a = $b ]
then
echo "a 等于 b"
fi
双分支结构
行一次条件匹配,如果与条件匹配,则执行相应的预设命令,反之去执行不匹配的预设命令
语法结构:
if 条件
then
命令
else
命令
fi
#!/bin/bash
a="abc";
b="efg";
if [ $a = $b ]
then
echo "a 等于 b"
else
echo "a 不等于 b"
fi输出:
a 不等于 b
多分枝结构
进行多次条件判断,一次在匹配中匹配成功都会执行相应的预设命令
语法结构:
if 条件1
then
命令1
elif 条件2
then
命令2
elif 条件3
then 命令3
.......
else
命令N
fi
for
for循环语句允许脚本一次性读取多个文件信息,然后逐一对信息进行操作,每次赋值后即执行一次循环体; 直到列表中的元素耗尽,循环结束
语法组成:由for...in 、do 、done组成
for 变量名 in {取值列表} 取值列表:{n..N} 表示一个范围,或者提前定义一个文件,注入 内容
do
命令序列
done
使用:
for loop in 1 2 3 4 5
do
echo "The value is: $loop"
done输出:
The value is: 1
The value is: 2
The value is: 3
The value is: 4
The value is: 5
通常情况下 shell 变量调用需要加 $,但是 for 的 (()) 中不需要,下面来看一个例子:
#!/bin/bash
for((i=1;i<=5;i++));do
echo $i;
done;
双小括号方法,即((…))格式,也可以用于算术运算
while
whil和for 都为条件循环语句,二者的区别在于while的条件循环是不知道最终执行多少次(可定义结束时间)
而for是有使用范围和目标的。
循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判断;条件为“true”,则执行一次循环;直到条件测试状态为“false”终止循环
语法组成:由while true 、do 、done组成 或while : 、do 、done及while 条件判断 、do、done
where 条件判断
do
命令序列
done
#!/bin/bash
int=1
while(( $int<=5 ))
do
echo $int
let "int++"
done
case
case 语句可以使脚本程序的结构更加清晰、层次分明,常用于服务的启动、重启、停止的脚本,有的服务不提供这种控制脚本,需要用case语句编写
语法格式:
case 变量值 in
模式 1)
命令序列 1
;;
模式 2)
命令序列 1
;;
* )
默认命令序列
esac
#!/bin/bash
NUM=4
case $NUM in
1)
echo NUM == 1
;;
2)
echo NUM == 2
;;
3)
echo NUM == 3
;;
4)
echo NUM == 4
;;
*)
echo xxxxx
;;
esac输出:
NUM == 4
case支持glob风格的通配符:*
: 任意长度任意字符?
: 任意单个字符[]
:指定范围内的任意单个字符a|b
: a或b
函数
Shell 函数的本质是一段可以重复使用的脚本代码,这段代码被提前编写好了,放在了指定的位置,使用时直接调取即可
格式
function name() {
statements
[return value]
}
function :关键字,用来定义函数
name:函数名
statements:函数要执行的代码
[return value]:函数的返回值,返回值可写可不写
由{}包裹的部分称为函数体,调用一个函数,实际上就是执行函数体中的代码
不带参数没有返回值的函数
#!/bin/bash
hello(){
echo "这是我的第一个 shell 函数!"
}
echo "-----函数开始执行-----"
hello
echo "-----函数执行完毕-----"输出结果:
-----函数开始执行-----
这是我的第一个 shell 函数!
-----函数执行完毕-----
有返回值的函数
#!/bin/bash
funWithReturn(){
echo "输入第一个数字: "
read aNum
echo "输入第二个数字: "
read anotherNum
echo "两个数字分别为 $aNum 和 $anotherNum !"
return $(($aNum+$anotherNum))
}
funWithReturnecho "输入的两个数字之和为 $?"
输出结果:
输入第一个数字:
1
输入第二个数字:
2
两个数字分别为 1 和 2 !
输入的两个数字之和为 3
带参数的函数
#!/bin/bash
funWithParam(){
echo "第一个参数为 $1 !"
echo "第二个参数为 $2 !"
echo "第十个参数为 $10 !"
echo "第十个参数为 ${10} !"
echo "第十一个参数为 ${11} !"
echo "参数总数有 $# 个!"
echo "作为一个字符串输出所有参数 $* !"
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73输出结果:
第一个参数为 1 !
第二个参数为 2 !
第十个参数为 10 !
第十个参数为 34 !
第十一个参数为 73 !
参数总数有 11 个!
作为一个字符串输出所有参数 1 2 3 4 5 6 7 8 9 34 73 !
$10 不能获取第十个参数,获取第十个参数需要${10}。当n>=10时,需要使用${n}来获取参数
另外,还有几个特殊字符用来处理参数:
输入/输出重定向
执行一个命令时,通常会打开3个文件,标准输入文件(stdin)、标准输出文件(stdout)、标准出错输出文件(stderr),分别对应的是键盘、屏幕、屏幕终端。
输入重定向符号
输入重定向符<
的作用是,把命令(或可执行文件)的标准输入重定向到制定文件,例如,在一个文件cmds
中包含以下内容:
cat cmds
echo "your working diretory is `pwd`"
echo "your name is `logname`"
echo "The time is `date`"
who
然后输入:
bash < cmds
shell命令解释程序从cmds中读取命令行并执行 输入重定向的一般形式是:
命令<文件名
输出重定向符号
输出重定向符>
的作用是,把命令(或可执行程序)的标准输出重新定向到指定文件中,例如:shell脚本exp1的内容如下:
echo "The time is `date`"
echo "Your name is `logname`"
echo "Working diretory is `pwd`"
echo "It has `ls -l|wc -l` files."
执行下列命令:
exp1 > tmp1
输出重定向的一般形式是:
命令>文件名
输出附加定向符
输出附加定向符>>
的作用是,把命令(或可执行程序)的输出附加到指定文件的后面,而该文件原有内容不被破坏,例如:
ps -l >> psfile
把ps
命令的输出附加到文件psfile
的结尾处。利用cat
命令就可看到psfile
的全部信息,包括原有内容和新添内容。
使用输出附加定向符时,如果指定文件不存在,就创建一个新文件,输出附加定向符的一般形式是:
命令 >> 文件名
即时文件定向符
即时文件有重新定向符<<
、一对标记符以及若干输入行组成,它允许把shell程序的输入行重新定向到一个命令,即时文件的形式是:
命令 [参数]«标记符 输入行 标记符
与文件描述字有关的重定向
每一个打开的文件都有系统赋予的一个文件描述字,它是一个小整数。一个文件打开后,用户可以直接用这个描述子来引用对应的文件。如前所述,系统为每个进程自动打开三个标准文件(即校准输入、标准输出和错误输出),其文件描述字分别是0,1,2。 前面已经列举了标准输入和标准输出重新定向的例子。标准错误也可重定向倒一个文件中,其一般形式是:
命令 2>文件名 命令 2>>文件名