shell学习记录
shell是什么
简单来说,shell是一个命令解释器,将用户输入的命令解释给操作系统内核。它既是命令语言又是程序设计语言。Shell 同时也是一个程序,它的一端连接着 UNIX/Linux 内核,另一端连接着用户和其它应用程序;换句话说,Shell 是用户和应用程序与内核沟通的桥梁。
类型:sh、bash、ash、csh(tcsh)、ksh、zch
shell的功能
- Shell 除了能解释用户输入的命令,将它传递给内核,还可以:
调用其他程序,给其他程序传递数据或参数,并获取程序的处理结果;
在多个程序之间传递数据,把一个程序的输出作为另一个程序的输入;
Shell 本身也可以被其他程序调用。 - 可以用shell做的事情: Linux 的日常管理工作,如文本或字符串检索、文件的查找或创建、大规模软件的自动部署、更改系统设置、监控服务器性能、发送报警邮件、抓取网页内容、压缩文件等。
linux运维工程师的工作细节
- 安装操作系统,例如 CentOS、Ubuntu 等。
- 部署代码运行环境,例如网站后台语言采用 PHP,就需要安装 Nginx、Apache、MySQL、PHP 运行时等。
- 及时修复漏洞,防止服务器被攻击,这包括 Linux 本身漏洞以及各个软件的漏洞。
- 根据项目需求升级软件,例如 PHP 7.0 在性能方面获得了重大突破,如果现在服务器压力比较大,就可以考虑将旧版的 PHP 5.x 升级到 PHP 7.0。
- 监控服务器压力,别让服务器宕机。例如淘宝双十一的时候就会瞬间涌入大量用户,导致部分服务器宕机,网页没法访问,甚至连支付宝都不能使用。
- 分析日志,及时发现代码或者环境的问题,通知相关人员修复。
什么是脚本
简而言之,脚本就是可执行的代码 shell脚本扩展名一般就是.sh(从上到下,逐句执行)
shell相关操作(交互)
- 查看当前使用的shell:echo $SHELL
- 查看系统可用的shell:cat /etc/shells
- 编写一个简单脚本:
touch 脚本名.sh
vi 脚本名.sh!/bin/bash ————第一行必须以特殊注释
脚本内容
:wq或者x ————保存退出
chmod a+x 脚本名.sh ————添加可执行权限
./脚本名.sh ————执行脚本
不想修改权限的操作:/bin/bash 脚本名.sh
- 进入shell的方法:
1、进入linux控制台 :ctrl+alt+F123456 +7切换回图形化界面
输入账户和密码进入控制台模式,然后出现$ (shell命令提示符)
2、终端
对于普通用户,Base shell 默认的提示符是美元符号$;对于超级用户(root 用户),Bash Shell 默认的提示符是井号#。该符号表示 Shell 等待输入命令。
shell相关语法
输出命令 echo
(未理解)Shell 通过PS1和PS2两个环境变量来控制提示符格式:
PS1 控制最外层命令行的提示符格式。
PS2 控制第二层命令行的提示符格式。Shell 使用以\为前导的特殊字符来表示命令提示符中包含的要素,这使得 PS1 和 PS2 的格式看起来可能有点奇怪。下表展示了可以在 PS1 和 PS2 中使用的特殊字符。
-
read输入文件读取键盘输入
!/bin/bash
echo "what is your name?"
read PERSON
echo "Hello,$PERSON" 获取当前进程pid echo $$(进程的pid一样就是在同一个进程)
source命令 强制执行脚本文件中的全部命令,而忽略脚本文件的权限。
语法:source 文件名 简写 . 文件名(点和文件名中间有个空格)
注意:应该是要切换到脚本所在的目录注释 #
变量与变量作用域
变量
- 定义变量的三种方式
变量名=变量值,变量名='变量值',变量名="变量值"
赋值号 = 的周围不能有空格, 值没有空白符变量可以不用引号,值有空白符一定要用引号,单引号不能解释特殊变量(原样输出使用),所以建议使用双引号
- 变量的命名规则
变量名由数字、字母、下划线组成;
必须以字母或者下划线开头;
不能使用 Shell 里的关键字(通过 help 命令可以查看保留关键字)。 - 使用变量变量名的前面加上$符号即可,为了帮助解释器识别变量边界可以加个{},推荐给所有变量加上花括号{ },这是个良好的编程习惯。
- 修改变量 ———> 对变量重新赋值即可
- 命令赋值给变量 变量名=
命令名
(这是反引号) 或者 变量名=变量名 => 输出的命令执行的内容 - 只读变量 定义变量后,下一行添加readonly 变量名(值不可变)
- 删除变量 同只读变量一样 添加unset 变量名(可以选择不去定义)
特殊变量
位置参数(与Python中的关键字参数)与特殊参数
- 位置参数:通过$n的形式来接收的参数
- 特殊参数:#(传给的参数个数)
@(传递的所有参数)
$?(上个命令的退出状态,或者函数的返回值)
$$(当前进程的pid)
不用双引号时候没有区别(都是将接收到的每个参数看做一份数据,彼此之间以空格来分隔),当它们被双引号" "包含时,就会有区别了(需要通过for循环才能看出区别):
"@"仍然将每个参数都看作一份数据,彼此之间是独立的。
"?",获取函数的返回值
#!/bin/bash
#得到两个数相加的和
function add(){
return `expr $1 + $2`
}
add 23 50 #调用函数
echo $? #获取函数返回值
变量作用域
有的变量可以在当前 Shell 会话中使用,这叫做全局变量(global variable),函数中变量名前面未加local的也是全局变量,全局变量只在当前 Shell 会话中有效,如果使用export命令(export 变量名)将它导出,那么它就在所有的子 Shell 中也有效了,这称为“环境变量”(环境变量只能向下传递而不能向上传递,即“传子不传父”。可以通过exit层层退出shell);
有的变量只能在函数内部使用,这叫做局部变量(local variable);
而有的变量还可以在其它 Shell 中使用,这叫做环境变量(environment variable)。
如果想让环境变量在所有 Shell 中都有效,并且能够永久保存,在关闭 Shell 后也不丢失,那么就需要把环境变量写入启动文件。
字符串
- 字符串的定义,字符串的定义形式和变量的定义一样
- 由单引号' '包围的字符串:
任何字符都会原样输出,在其中使用变量是无效的。
字符串中不能出现单引号,即使对单引号进行转义也不行。 - 由双引号" "包围的字符串:
如果其中包含了某个变量,那么该变量会被解析(得到该变量的值),而不是原样输出。
字符串中可以出现双引号,只要它被转义了就行。 - 不被引号包围的字符串
不被引号包围的字符串中出现变量时也会被解析,这一点和双引号" "包围的字符串一样。
字符串中不能出现空格,否则空格后边的字符串会作为其他变量或者命令解析。
- 获取字符串的长度 ${#字符串名}
- 字符串拼接(只有不加引号或者加双引号) 两个字符串并排放在一起就能实现拼接,双引号中的变量名一定要用{}划分边界
- 字符串的截取:
- 指定位置开始截取:
- 字符创左边开始截取:{string: 0-start :length}
从左边开始计数时,起始数字是 0(这符合程序员思维);从右边开始计数时,起始数字是 1(这符合常人思维)。计数方向不同,起始数字也不同。
不管从哪边开始计数,截取方向都是从左到右。
- 制定字符开始截取
- 使用 # 号截取右边字符 ${string#*chars} 忽略第一个chars左边所有字符(截取内容不包含这个chars) 用## 匹配最后一个才会结束
- 使用 % 号截取左边字符 ${string%chars* } 请注意 * 的位置,因为要截取 chars 左边的字符,而忽略 chars 右边的字符,所以*应该位于 chars 的右侧。
八种用法:
${string: start :length} 从 string 字符串的左边第 start 个字符开始,向右截取 length 个字符。
${string: start} 从 string 字符串的左边第 start 个字符开始截取,直到最后。
${string: 0-start :length} 从 string 字符串的右边第 start 个字符开始,向右截取 length 个字符。
${string: 0-start} 从 string 字符串的右边第 start 个字符开始截取,直到最后。
${string#*chars} 从 string 字符串第一次出现 *chars 的位置开始,截取 *chars 右边的所有字符。
${string##*chars} 从 string 字符串最后一次出现 *chars 的位置开始,截取 *chars 右边的所有字符。
${string%*chars} 从 string 字符串第一次出现 *chars 的位置开始,截取 *chars 左边的所有字符。
${string%%*chars} 从 string 字符串最后一次出现 *chars 的位置开始,截取 *chars 左边的所有字符。
数组
常用的 Bash Shell 只支持一维数组,不支持多维数组
- 定义数组 用括号( )来表示数组,数组元素之间用空格来分隔
数组名=(元素1 元素2 ...) - 获取数组元素用:使用下标[ ],下标可以是一个整数,也可以是一个结果为整数的表达式;当然,下标必须大于等于 0。${array_name[index]},使用@或*代替下标可以获取数组中的所有元素。
- 添加元素:数组名[长度]=元素值,会在数组后面添加元素
- 修改数组:数组名=([下标]=值 ...)
- 获取数组长度:利用@或 * ,可以将数组扩展成列表,然后使用#来获取数组元素的个数,格式如下:{#array_name[ * ]}
- 数组拼接:先利用@或,将数组扩展成列表,然后再合并到一起
array_new=({array2[@]})
array_new=({array2[]}) - 删除数组元素 unset array_name[index]
- 删除数组 unset array_name
- 关联数组 关联数组必须使用带有-A选项的 declare 命令创建。
访问关联数组元素 array_name["index"] 获取值$(array_name["index"])
运算符与表达式
- 数学运算
shell默认所有变量都是字符串,执行数学计算需要用[]括起来
a=100
echo $[$a+10]
echo $[$a / 2]
echo $[$a * 2]
echo $[$a - 80]
echo $[10 % 2]
echo $((3 + 5))
echo $((10/2))
echo $((10/3)) #3 整除
echo $((10*3))
echo $((10%3))
let a=5+6
echo $a
let a+=10
echo $a
echo `expr 3 + 5` #也可以用expr进行计算
-
关系运算
运算符 说明 举例 -eq ==,相等返回 true。 [ $a -eq $b
] 返回 false。-ne !=,不相等返回 true。 [ $a -ne $b
] 返回 true。-gt >
,如果是,则返回 true。[ $a -gt $b
] 返回 false。-lt <,如果是,则返回 true。 [ $a -lt $b
] 返回 true。-ge >=
,如果是,则返回 true。[ $a -ge $b
] 返回 false。-le <=
,如果是,则返回 true。[ $a -le $b
] 返回 true。 -
逻辑运算
运算符 说明 举例 && 逻辑的 AND [[ $a -lt 100 && $b
-gt 100 ]] 返回 false|| 逻辑的 OR [[ b -gt 100 ]] 返回 true -
字符串判断
运算符 说明 举例 = 检测两个字符串是否相等,相等返回 true。 [ $a = $b
] 返回 false。!= 检测两个字符串是否相等,不相等返回 true。 [ b ] 返回 true。 -z 检测字符串长度是否为0,为0返回 true。 [ -z $a ] 返回 false。 -n 检测字符串长度是否为0,不为0返回 true。 [ -n "$a" ] 返回 true。 str 检测字符串是否为空,不为空返回 true。 [ $a ] 返回 true。 -
文件判断
操作符 说明 举例 -d file 检测文件是否是目录,如果是,则返回 true。 [ -d $file ] 返回 false。 -f file 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 [ -f $file ] 返回 true。 -r file 检测文件是否可读,如果是,则返回 true。 [ -r $file ] 返回 true。 -w file 检测文件是否可写,如果是,则返回 true。 [ -w $file ] 返回 true。 -x file 检测文件是否可执行,如果是,则返回 true。 [ -x $file ] 返回 true。 -s file 检测文件是否为空(文件大小是否大于0),不为空返回 true。 [ -s $file ] 返回 true。 -e file 检测文件(包括目录)是否存在,如果是,则返回 true。 [ -e $file ] 返回 true。
分支语句
一、单分支if语句
- 语法格式
复制代码
if [ 条件判断式 ]; then
程序
fi
或者
if [ 条件判断式 ]
then
程序
fi
注意:中括号和条件判断式之间必须有空格
复制代码
- 示例1:判断登陆的用户是否是root
复制代码
!/bin/bash
if [ "$USER" == root ];then
echo "Login User is root"
fi
#########或者#########
!/bin/bash
if [ "$USER" == root ]
then
echo "Login User is root"
fi
复制代码
- 示例2:判断分区使用率
复制代码
!/bin/bash
test=5}' | cut -d '%' -f 1)
if [ $test -ge 90 ];then
echo "Warning! /dev/sda1 is full!"
fi
复制代码
二、双分支if语句
- 语法格式
复制代码
if [ 条件判断式 ]; then
条件成立时,执行的程序
else
条件不成立时,执行的程序
fi
或者
if [ 条件判断式 ]
then
条件成立时,执行的程序
else
条件不成立时,执行的程序
fi
复制代码
- 示例1:输入一个文件,判断是否存在
复制代码
!/bin/bash
read -p "Please input a file:" file
if [ -f file exists!"
else
echo "File: $file not exists!"
fi
复制代码
- 示例2:判断apache服务是否启动了,如果没有启动,就代码启动
复制代码
!/bin/bash
test=$(ps aux | grep httpd | grep -v 'grep' | wc -l)
if [ (date) httpd is running!"
else
echo "$(date) httpd isn't running, will be started!"
/etc/init.d/httpd start
fi
复制代码
三、多分支if语句
- 语法格式
复制代码
if [ 条件判断式1 ]; then
当条件判断式1成立时,执行程序1
elif [ 条件判断式2 ]; then
当条件判断式2成立时,执行程序2
.....省略更多条件.....
else
当所有条件都不成立时,最后执行此程序
fi
复制代码
- 示例:实现计算器
复制代码
!/bin/bash
输入数字a,数字b和操作符
read -p "Please input number a:" a
read -p "Please input number b:" b
read -p "Please input operator[+|-|*|/]:" opt
判断输入内容的正确性
testa=a | sed 's/[0-9]//g')
testb=a | sed 's/[0-9]//g')
testopt=opt | sed 's/[+|-|*|/]//g')
if [ -n "testb" -o -n "opt" == "+" ]; then
result=a+opt" == "-" ]; then
result=a-opt" == "" ]; then
result=a((b))
fi
echo "a result"
复制代码
四、case语句
case语句和if...elif...else语句都是多分支条件语句,不过和if多分支条件语句不同的是,case语句只能判断一种条件关系,而if语句可以判断多种条件关系。
- 语法格式
复制代码
case $变量名 in
"值1")
如果变量的值等于值1,则执行程序1
;;
"值2")
如果变量的值等于值2,则执行程序2
;;
.....省略其他分支.....
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac
复制代码
- 示例:判断用户输入
复制代码
!/bin/bash
read -p "Please choose yes/no:" cmd
case $cmd in
"yes")
echo "Your choose is yes!"
;;
"no")
echo "Your choose is no!"
;;
*)
echo "Your choose is error!"
;;
esac
复制代码
循环语句
一、for循环
语法格式1
for 变量 in 值1 值2 值3 ...
do
程序
done
说明:程序将遍历所有的值,赋值给变量,然后在执行程序。也就是说,后面接多少个值,程序就循环多少次。示例1:遍历5个数,进行输出
复制代码
!/bin/bash
for i in 1 2 3 4 5
do
echo $i
done
输出结果
1
2
3
4
5
复制代码
- 示例2:遍历目录下的所有文件,进行输出文件名
!/bin/bash
for file in file
done
- 语法格式2
for (( 初始值;循环控制条件;变量变化 ))
do
程序
done
说明:这种格式和C语言for循环的格式是一样的,区别只是需要用双括号括住循环条件。
- 示例1:计算1到100的总和
复制代码
!/bin/bash
sum=0
for ((i=1;i<=100;i=i+1))
do
sum=sum+[i]
done
echo $sum
输出
5050
复制代码
二、while循环
- 语法格式
while [条件判断式]
do
程序
done
说明:当条件判断式成立时,才会执行程序,直到条件判断式不成立时,才退出循环。
- 示例:计算1到100的总和
复制代码
!/bin/bash
i=1
sum=0
while [ (( sum+i ))
i=$(( i+1 ))
done
echo $sum
输出
5050
复制代码
三、until循环
- 语法格式
until [条件判断式]
do
程序
done
说明:until循环和while循环是相反的,当条件判断式不成立时,才会执行程序,直到条件判断式成立,才退出循环。
- 示例:计算1到100的总和
复制代码
!/bin/bash
i=1
sum=0
until [ (( sum+i ))
i=$(( i+1 ))
done
echo $sum
输出结果
5050
复制代码
函数(实现模块化)
- 函数的定义
- name() {
statements
[return value]
}
-function name {
statements
[return value]
}
- name() {
- 函数的调用
直接函数名调用
带参数:函数名 参数1 参数2 ... (参数之间空格隔开即可)
输出返回值 可以转为全局变量输出,或者用echo函数和printf命令
shell常用内置命令
- 别名
添加别名 alias 命名名=‘别名’
删除别名 unalias 别名 - 输出
echo - 输入
read [-options] [variables]
options表示选项,如下表所示;variables表示用来存储数据的变量,可以有一个,也可以有多个。
options和variables都是可选的,如果没有提供变量名,那么读取的数据将存放到环境变量 REPLY 中。 - 退出进程
exit - 设置变量属性
declare [+/-] [aAfFgilprtux] [变量名=变量值]