![5439e5e38f06b38400dc8b8dbf3523ef.png](https://i-blog.csdnimg.cn/blog_migrate/250feb9846ee961cf5863abb65885557.jpeg)
什么是Shell?
- Shell 是 Linux 的命令解释器,用于解释用户对操作系统的操作
- cat /etc/shells
- CentOS 7 默认使用的 Shell 是 bash
- 命令执行的具体过程: 由 Shell 接受命令,对命令的选项和参数进行分析。如 ls,会交给文件系统(内核),内核接受命令,将所要查看的目录或文件翻译成硬盘的某个扇区,硬件将查询到的结果返回给内核,内核返回给 Shell ,Shell 返回给用户。
- bash 是基于bsh,将其他 shell 好用的功能集成过来,bsh 不好用的省略,a 代表 again重写。
Linux 的启动过程
- 系统自带的 Shell 脚本用途
- 用于 Linux 系统的启动过程
- Linux 命令
2. Linux 启动过程
BIOS引导 - MBR - BootLoader(grub) - kernel - systemd - 系统初始化 - shell
BIOS基本输入输出系统在主板上,通过BIOS选择引导的介质(硬盘/光盘),来到硬盘,MBR主引导记录部分,可引导则进入grub,启动和引导内核/windows系统,grub用于选择内核和内核版本,启动kernel,内核初始化-加载硬件,一号进程:systemd(CentOS 7)/init(CentOS)
- 查看MBR:dd if=/dev/sda of=mbr.bin bs=512 count=1
- hexdump -C mbr.bin.
- 55 aa 证明扇区引导正确 446bytes
- 查看 grub: cd /boot/grub2
- 查看内核版本:grub2-editenv list uname -r
- 查看 systemd:cd /etc/systemd/system/
Shell 脚本的格式
为了组合命令和多次执行,使用脚本文件保存需要执行的命令。文件拓展名 .sh
赋予该文件的权限 chmod u+rx filename
执行:bash filename.sh 默认命令解释器为 bash 才可以
./filename. sh 用系统默认的命令解释器
#!/usr/bin/python
#!/bin/bash
bash ./filename.sh 被解释为注释
./filename.sh 被解释为 /bin/bash 运行
![f288d1fe3936927f44ad025b2182ce4f.png](https://i-blog.csdnimg.cn/blog_migrate/d4911b6afeda405f5700b113544e98d3.jpeg)
脚本不同执行方式的影响
- bash ./filename.sh 开启bash子进程执行,无需X权限,运行后回到父进程,不改变环境
- ./filename.sh 开启sha-Bang子进程运行,必须赋予x权限,运行后回父进程,环境不变
- source ./filename.sh 当前进程运行,改变环境,无需X权限
- . filename.sh 当前进程运行,改变环境,无需X权限
内建命令和外部命令的区别
- 内建命令不需要创建子进程
- 内建命令对当前shell生效
管道与重定向
- 管道:进程通信工具,方便脚本编程两条命令相互通信
- 匿名管道(管道符):Shell 编程经常用到的通信工具
- 管道符是“|”,将前一个命令的执行结果传递给后面的命令 ps | cat 、 echo 123 | ps,给前后两个命令创建子进程,如果子进程中存在内建命令是不会传递给父进程,所以使用管道符尽量不要使用内建命令。如果子进程是shell,则称为子shell
- 重定向:进程运行时会打开stdin stdout stderr 三个文件描述符,标准输出信息输出到文件
输入重定向: '<' 文件代替键盘输入
read var < /path/to/a/file
输出重定向: '>' '>>' '2>' '&>' 文件代替终端输出
清空:echo 123 > /path/to/a/file
换行追加:echo 123 >> /path/to/a/file
错误重定向:echo 123 2> /path/to/a/file
全部执行信息重定向:echo 123 &> /path/to/a/file
输入输出重定向组合使用:
cat > /path/to/a/file << EOF
I am $USER
EOF
变量
- 变量的赋值
- 变量名=变量值 abc=123
- 使用let为变量赋值 let a=10+20
- 将命令赋值给变量 l=ls
- 将命令结果赋值给变量 使用$()或者'' letc=$(ls -l /etc)
- 变量值有特殊字符可以包含在" " 、 ' '中
2.变量的引用
- ${变量名}称作对变量的引用
- echo ${变量名} 查看变量的值
- ${变量名} 在部分情况下可省略为$变量名
3.变量的默认作用范围 :本shell
变量的导出 export 变量名 子进程可以获得父进程的变量值
变量的删除 unset 变量名
4. 环境变量、预定义变量、位置变量
- 系统环境变量:每一个shell都可以读取到变量值
每一个系统环境变量都经历了export的导出,子shell可以生效
set 和 env 命令
echo $PATH 若想修改PATH 可以 export PATH=$PATH:/new/path,子shell可以生效(bash 产生子shell),平行shell不生效
$PS1
- 位置变量:$1 $2 .${10}.. $n. 对应入参。若读入值为空可 var=${2-_} echo var
- 预定义变量:echo $? 上一条命令正确执行 0。错误执行 1
- echo $$ 显示当前进程Pid
- echo $0 显示当前进程名称
5. 环境变量的配置文件
etc保存所有用户配置,~家目录保存用户特有配置.
配置文件在打开终端的时候才运行
login in :su - username 执行五个配置文件,加载全面
no login in: su username 执行下面两个配置文件,加载不全
- /etc/profile
- /etc/profile.d/
- ~/.bash_profile
- ~/.bashrc alias
- /etc/bashrc
数组
- 定义数组: IPTS=(1 2 3)
- 显示数组所有元素: echo ${IPTS[@]}
- 显示数组元素个数: echo ${#IPTS[@]}
- 显示数组的第一个元素: echo ${IPTS[0]}
算术运算符
- + - / ** %
- 运算 expr 4 + 5. expr只支持整数
- num1 = `expr 4 + 5`. ((num1=4+5))
数字常量
- let "变量名=变量值"
- 0开头为八进制,0x为十六进制
- 双圆括号是 let 命令的简化,((a=10)) ((a++)) echo $((10+20))
特殊字符大全
引用:
' 完全引用,不进行解释$
" 不完全引用,进行解释$
` 执行命令
![0c893e43cb856415309b7cc37973330c.png](https://i-blog.csdnimg.cn/blog_migrate/f9e1862e0774a6a46970140f48037346.jpeg)
退出与退出状态
- exit shell 运行成功返回0 失败返回非0 使用 echo $? 查看上一个进程是否正常退出
- exit 127 返回一个自定义值
测试命令 test
- test 命令用于检查文件或者比较值
- test 可以做以下测试:文件测试、整数比较测试、字符串测试
- test 测试语句可以简化为 []
- [] 符号还有拓展写法[[]] 支持&&、||、<、>
man test
判断是否为文件:test -f /etc/passwd 存在为0 不存在为1
判断值大小:[5 -gt 4] [[5>4]] gt lt ge le eq
判断目录是否存在:[-e /etc/]
判断字符串是否相等: ["abc"="ABC"] 结果为1,test可以区分大小写
语句
if-then 语句
if [测试条件成立] 或 命令返回值是否为0
then 执行相应命令
fi 结束
if-then-else 语句
if [测试条件成立] 或 命令返回值是否为0
then 执行相应命令
else 测试条件不成立,执行相应命令
fi 结束
#!/bin/bash
# if else
if [$USER = root];then
echo "user root"
echo $UID
else
echo "other root"
echo $UID
fi
if-elif-else 语句
if [测试条件成立] 或 命令返回值是否为0
then 执行相应命令
elif [测试条件成立] 或 命令返回值是否为0
then 执行相应命令
else 测试条件不成立,执行相应命令
fi 结束
#!/bin/bash
# if elif else
if [$USER = root];then
echo "user root"
echo $UID
elif [$USER = user1];then
echo "user root"
echo $UID
else
echo "other root"
echo $UID
fi
嵌套if的使用
if [测试条件成立] 或 命令返回值是否为0
then 执行相应命令
if [测试条件成立] 或 命令返回值是否为0
then 执行相应命令
fi 结束
fi 结束
分支语句
case "$变量" in
"情况1" )
命令...;;
"情况2" )
命令...;;
* )
命令...;;
esac
![22114ef1ec96331f695de1dd717126b4.png](https://i-blog.csdnimg.cn/blog_migrate/9c1969f9c8037dc2596679d0f958bf41.png)
for 循环
for 参数 in 列表
do 执行的命令
done 封闭一个循环
使用反引号或者$()方式执行的命令,命令的结果当作列表进行处理
for i in {1..9}
do
echo $i
done
c语言的风格的(awk使用):
for((赋值;判断;变化))
do
循环执行的命令
done
while 循环和 util 循环
使用循环处理命令行参数
命令行参数可以使用 $1 $2 $3 ${10} $n进行读取
$0 代表脚本名称
$@ 和 $*可以代表所有位置的参数
$#代表位置参数的数量
for pos in $*
do
if ["$pos"="help"];then
echo $pos $pos
fi
done
while [$# -ge 1]
do
if ["$1"="help"];then
echo $1 $1
fi
shift //可以参数左移
done
自定义函数
自定义函数:
function fname(){ //function 可省略
命令
}
函数的执行:
fname
函数作用范围的变量: local 变量名
删除函数:unset fname
----------------------------------
cdls(){
cd $1
ls
}
调用:cdls /tmp 进入tmp并进行查看
----------------------------------
每个进程对应在/proc/pid目录下
checkpid(){
local i
for x in $* ;do
[-d "/proc/$x"] && return 0
done
return 1
}
执行: checkpid 1
echo $?
系统函数库介绍
系统自建了函数库,可以在脚本中引用 /etc/init.d/functions
自建函数库:
使用source函数脚本文件"导入"函数
脚本资源配置
脚本优先级控制
- 可以使用 nice 和 renice 调整脚本优先级
- 避免出现不可控的死循环(cpu 占用高/死机)
查看限制:ulimit -a
root用户中的很多限制不生效 可能会产生fork炸弹 .() {. | .&}; .
信号捕获
捕获信号脚本的编写:
kill 默认会发送15号信号给应用程序
ctrl +c 默认会发送2号信号给应用程序
9号信号不可阻塞
#!/bin/bash
#capture signal
trap "echo sig 15" 15 // kill -15 pid
trap "echo sig 2" 2 // ctrl+c
echo $$ // 打印进程号
while : // 死循环
do
:
done
计划任务
一次性计划任务 at
at 指定时间
echo hello > /tmp/hello.txt
ctrl+d 提交
查看计划任务:atq周期性计划任务
周期性计划任务
配置方式: crontab -e
每分钟运行显示系统的日期:
* * 7 7 1-5 /usr/bin/date >> /tmp/date.txt。 七月七日,若在周一到周五范围内,每分钟执行一次
查看任务: cd /var/log. tail -f cron
查看现有的计划任务: crontab -l
每个用户周期性计划任务文件: /var/spool/cron/
配置格式:分钟 小时 日期 月份 星期执行的命令
计划任务加锁 flock
如果计划 1:30 完成某个计划任务,但在 1:25 宕机 则可以使用此解决方案
即,计算机不能按照预期时间运行
anacontab 延时计划任务
flock 锁文件
flock -xn "tmp/f.lock" -c "root/task_shell_file". 排它 保证一次只能运行一个实例