1. 使用while read line和/etc/passwd,计算用户id总和。
2. 总结索引数组和关联数组,字符串处理,高级变量使用及示例。
索引数组:
引用特定的数组元素
${ARRAY_NAME[INDEX]}
注:如果省略[INDEX]表示引用下标为0的元素
引用数组所有元素
${ARRAY_NAME[*]}
${ARRAY_NAME[@]}
数组个数
${#ARRAY_NAME[*]}
数组下标
${!ARRAY_NAME[*]}
关联数组:
注意:关联数组必须先声明再调用
declare -A ARRAY_NAME
ARRAY_NAME=([idx_name1]='val1' [idx_name2]='val2‘...)
基于偏移量取字符串
基于模式取字符串
${var#*word}:删除从开头到第一个word之间所有的字符(懒惰模式)
${var##*word}:删除从开头到最后一个word之间所有的字符(贪婪模式)
${var%word*}:删除从结尾到第一个word之间所有的字符
${var%%word*}:删除从结尾到最后一个word之间所有的字符
查找替换
${var/pattern/substr}:查找变量var中第一次被pattern匹配的字符串,并替换为substr
${var//pattern/substr}:查找变量var中所有被pattern匹配的字符串,并替换为substr
${var/#pattern/substr}:查找变量var中行首被pattern匹配的字符串,并替换为substr
${var/%pattern/substr}:查找变量var中行尾被pattern匹配的字符串,并替换substr
小写转换成大写:
大写转换成小写:
高级变量用法:
eval会执行两次,第一个替换变量,第二次执行命令
3. 求10个随机数的最大值与最小值。
4. 使用递归调用,完成阶乘算法实现。
3. 解析进程和线程的区别?
进程是操作系统分配资源的最小单位
线程是程序执行的CPU调度的最小单位
一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线;
进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间(包括代码段、数据集、堆等)及一些进程级的资源(如打开文件和信号),某进程内的线程在其它进程不可见;
调度和切换:线程上下文切换比进程上下文切换要快得多。
4. 解析进程的结构。
内核把进程存放在叫做任务队列(task list)的双向循环链表中
链表中的每一项都是类型为task_struct,称为进程控制块(Processing Control Block),PCB中包含一
个具体进程的所有信息
进程控制块PCB包含信息:
进程id、用户id和组id
程序计数器
进程的状态(有就绪、运行、阻塞)
进程切换时需要保存和恢复的CPU寄存器的值
描述虚拟地址空间的信息
描述控制终端的信息
当前工作目录
文件描述符表,包含很多指向file结构体的指针
进程可以使用的资源上限(ulimit –a命令可以查看)
输入输出状态:配置进程使用I/O设备
5. 解析磁盘中的代码如何在计算机上运行的?
每个进程都包括5种不同的数据段
代码段:用来存放可执行文件的操作指令,也就是说是它是可执行程序在内存中的镜像。代码段需
要防止在运行时被非法修改,所以只准许读取操作,而不允许写入(修改)操作——它是不可写的
数据段:用来存放可执行文件中已初始化全局变量,换句话说就是存放程序静态分配的变量和全局
变量BSS段:Block Started by Symbol”的缩写,意为“以符号开始的块,BSS段包含了程序中未初始化的
全局变量,在内存中 bss段全部置零
堆(heap):存放数组和对象,堆是用于存放进程运行中被动态分配的内存段,它的大小并不固
定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上
(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)
栈(stack):栈是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量
(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,
其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。
由于栈的后进先出特点,所以栈特别方便用来保存/恢复调用现场。可以把堆栈看成一个寄存、交
换临时数据的内存区
喝多了吐就是栈
吃多了拉就是队列
6. 总结OOM原理,及处理方法。
OOM 即 Out Of Memory,“内存用完了”,在情况在java程序中比较常见。系统会选一个进程将之杀死,
在日志messages中看到类似下面的提示
Jul 10 10:20:30 kernel: Out of memory: Kill process 9527 (java) score 88 or sacrifice child
当JVM因为没有足够的内存来为对象分配空间并且垃圾回收器也已经没有空间可回收时,就会抛出这个
error,因为这个问题已经严重到不足以被应用处理)。
原因:
给应用分配内存太少:比如虚拟机本身可使用的内存(一般通过启动时的VM参数指定)太少。
应用用的太多,并且用完没释放,浪费了。此时就会造成内存泄露或者内存溢出。
使用的解决办法:
1,限制java进程的max heap,并且降低java程序的worker数量,从而降低内存使用
2,给系统增加swap空间
7. 结合进程管理命令,说明进程各种状态。
进程的基本状态
创建状态:进程在创建时需要申请一个空白PCB(process control block进程控制块),向其中填写
控制和管理进程的信息,完成资源分配。如果创建工作无法完成,比如资源无法满足,就无法被调
度运行,把此时进程所处状态称为创建状态
就绪状态:进程已准备好,已分配到所需资源,只要分配到CPU就能够立即运行
执行状态:进程处于就绪状态被调度后,进程进入执行状态
阻塞状态:正在执行的进程由于某些事件(I/O请求,申请缓存区失败)而暂时无法运行,进程受
到阻塞。在满足请求时进入就绪状态等待系统调用
终止状态:进程结束,或出现错误,或被系统终止,进入终止状态。无法再执行
状态之间转换六种情况
运行——>就绪:1,主要是进程占用CPU的时间过长,而系统分配给该进程占用CPU的时间是有限的;
2,在采用抢先式优先级调度算法的系统中,当有更高优先级的进程要运行时,该进程就被迫让出CPU,
该进程便由执行状态转变为就绪状态
就绪——>运行:运行的进程的时间片用完,调度就转到就绪队列中选择合适的进程分配CPU
运行——>阻塞:正在执行的进程因发生某等待事件而无法执行,则进程由执行状态变为阻塞状态,如发
生了I/O请求
阻塞——>就绪:进程所等待的事件已经发生,就进入就绪队列
以下两种状态是不可能发生的:
阻塞——>运行:即使给阻塞进程分配CPU,也无法执行,操作系统在进行调度时不会从阻塞队列进行挑
选,而是从就绪队列中选取
0 – Heuristic overcommit handling. 这是缺省值,它允许overcommit,但过于明目张胆的
overcommit会被拒绝,比如malloc一次性申请的内存大小就超过了系统总内存。Heuristic的意思是“试探
式的”,内核利用某种算法猜测你的内存申请是否合理,它认为不合理就会拒绝overcommit。
1 – Always overcommit. 允许overcommit,对内存申请来者不拒。内核执行无内存过量使用处理。使
用这个设置会增大内存超载的可能性,但也可以增强大量使用内存任务的性能。
2 – Don’t overcommit. 禁止overcommit。 内存拒绝等于或者大于总可用 swap 大小以及
overcommit_ratio 指定的物理 RAM 比例的内存请求。如果希望减小内存过度使用的风险,这个设置就是
最好的。就绪——>阻塞:就绪态根本就没有执行,谈不上进入阻塞态
进程更多的状态:
运行态:running
就绪态:ready
睡眠态:分为两种,可中断:interruptable,不可中断:uninterruptable
停止态:stopped,暂停于内存,但不会被调度,除非手动启动
僵死态:zombie,僵尸态,结束进程,父进程结束前,子进程不关闭,杀死父进程可以关闭僵死
态的子进程
8. 说明IPC通信和RPC通信实现的方式。
同一主机
不同主机
9. 通过mkfifo, cat, 来解释秒杀的并发问题,如何通过队列解决的?最好结合图形。说明消息队列的作用?
利用管道文件实现 IPC
10. 总结Linux,前台和后台作业的区别,并说明如何在前台和后台中进行状态转换。
Linux的作业控制
前台作业:通过终端启动,且启动后一直占据终端
后台作业:可通过终端启动,但启动后即转入后台运行(释放终端)
让作业运行于后台
运行中的作业: Ctrl+z
尚未启动的作业: COMMAND &
后台作业虽然被送往后台运行,但其依然与终端相关;退出终端,将关闭后台作业。如果希望送往后台
后,剥离与终端的关系
nohup COMMAND &>/dev/null &
screen;COMMAND
tmux;COMMAND
查看当前终端所有作业:[root@rocky8 2024-07-01]# jobs
作业控制:
fg [[%]JOB_NUM]:把指定的后台作业调回前台
bg [[%]JOB_NUM]:让送往后台的作业在后台继续运行
kill [%JOB_NUM]: 终止指定的作业
11. 总结内核设计流派及特点。
单内核设计:把所有功能模块集成于同一个程序(Linux),支持模块化如进程调度,内存管理,文件系统,硬件驱动等,支持模块的动态装载和卸载
微内核设计:每种功能模块使用一个单独子系统实现(Windows),把一些应用放到了用户空间,服务与服务之间隔离,单个服务故障或者被攻击,也不会导致操作系统挂掉
12. 总结rocky 启动流程,grub工作流程
1. 加载BIOS的硬件信息,获取第一个启动设备2. 读取第一个启动设备MBR的引导加载程序(grub)的启动信息
3. 加载核心操作系统的核心信息,核心开始解压缩,并尝试驱动所有的硬件设备
4. 核心执行init程序,并获取默认的运行信息
5. init程序执行/etc/rc.d/rc.sysinit文件,重新挂载根文件系统
6. 启动核心的外挂模块
7. init执行运行的各个批处理文件(scripts)
8. init执行/etc/rc.d/rc.local
9. 执行/bin/login程序,等待用户登录
10. 登录之后开始以Shell控制主机
GRUB 启动阶段
primary boot loader :
1st stage:MBR的前446个字节
1.5 stage:MBR 之后的扇区,让stage1中的bootloader能识别stage2所在的分区上的文件系统
secondary boot loader :2nd stage,分区文件/boot/grub/
13. 手写chkconfig服务脚本,可以实现服务的开始,停止,重启。
14. 总结systemd服务配置文件
systemd服务配置文件由三部分组成
[Unit]:定义与Unit类型相关的通用选项,用于提供unit描述消息,unit行为,依赖关系
[Service]:与特定类型相关的专用选项
[Install]:定义由systemclt enable/disable命令在实现服务开机启动或不启动时用到的一些选项
Unit段常用选项
Description:描述信息
After:定义unit的启动次序,表示当前unit应该晚于哪些unit启动
Requires:依赖到的其他units,被依赖的units无法激活时,当前unit也无法激活
Wants:依赖到的其他units
Conflicts:定义units间的冲突关系
Service段常用选项
Type:定义影响ExecStart及相关参数的功能的unit进程启动类型
ExecStart:指明启动unit要运行命令或脚本的绝对路径
ExecStop:指明停止unit要运行的命令或脚本
Install段常用选项
Alias:别名,可使用systemctl command Alias.service
RequiredBy:被哪些units所依赖
WantedBy:被哪些units所依赖
Also:安装被服务的时候还要安装别的相关服务
15. 总结system启动流程
POST加电自检
Bootloader,grub2启动引导程序:/etc/grub.d,/etc/default/grub,/boot/grub2/grub.cfg
解压initramfs文件,加载驱动模块,挂载根文件系统
加载虚拟根中的内核
虚拟根的内核初始化,运行第一个进程systemd
执行initrd.target所有单元
从initramfs根文件系统切换到磁盘根目录
systemd执行默认target配置,配置文件/etc/systemd/system/defaul.target
systemd执行sysinit.target初始化系统及basic.target准备操作系统
systemd启动multi-user.target下的本机与服务器服务
systemd执行multi-user.target下的/etc/rc.d/rc.local
systemd执行multi-user.target下的getty.target及登录服务
systemd执行graphical需要的服务
16. 总结awk工作原理,awk命令,选项,示例。
awk工作原理
第一步:执行BEGIN{action}语句
第二步:从文件或标准输入中读取一行,然后执行pattern{action}语句,与sed一样逐行扫描处理,从第一行到最后一行重复这个过程,知道全部被读取完毕
第三步:文件读取完毕后,执行END{action}语句
格式:awk [选项] ‘program’ [var=X] filename
选项:
-F:指定输入的字段分隔符,默认为若干个连续空白符
17. 总结awk的数组,函数。
awk数组为关联数组
关联下标可以为任意字符串,字符串要使用双引号
如果某数组元素不存在,在引用时,awk会自动创建此元素,并将其值初始化为空串
awk函数分为内置函数和自定义函数
数值处理
rand():返回1和0之间随机数
srand():配置rand函数,生成随机数种子
int():返回整数
字符串处理
length(X):返回指定字符串长度
sub(r,s,x):对x字符串搜索r表示模式匹配的内容,并将第一个匹配内容替换为s
gsub(r,s,x):对x字符串搜索r,并将匹配的所有内容替换为s
split(s,array,r):对r为分隔符,切割字符串s,并将切割后的结果保存至array数组
自定义函数
格式
function name(形参){
命令
return var
}
18. 总结ca管理相关的工具,根据使用场景总结示例。
创建CA相关文件
mkdir -p /etc/pki/CA/{certs,netwcerts,crl,private}
touch /etc/pki/CA/index.txt
echo 01 > /etc/pki/CA/serial
生成CA私钥
(umask 066;openssl genrsa -out /etc/pki/CA/private/cakey.pem
生成CA自签名证书
openssl req -new -x509 -key /etc/pki/CA/cakey.pem -out /etc/pki/CA/cacert.pem -days Num
生成用户私钥
(umask 066;openssl genrsa -out filename)
生成用户证书请求文件
openssl req -new -in filename -out filename
颁发用户证书
openssl ca -in filename -out filename -days Num
查看证书信息
openssl x509 -in filename -noout -text
吊销证书
echo 01 > /etc/pki/CA/crlnumber
openssl ca -revoke /etc/pki/CA/newcerts/Num.pem
openssl ca gencrl -out /etc/pki/CA/crl.pem
19. 总结对称加密和非对称加密算法和用openssl签发证书步骤
对称加密算法
加密和解密使用同一个密钥
特性:
加密、解密使用同一个密钥,效率高
将原始数据分割成固定大小的块,逐个进行加密
缺陷:
密钥多
密钥分发
数据来源无法确认
常用对称加密算法:
DES,3DES,AES
非对称加密算法
密钥成对出现
公钥:公开给所有人
私钥:自己留存,保证私密性
特点:用公钥加密,只能使用与之匹配的私钥解密,反之亦然
缺陷:
密钥长,算法复杂
加密解密效率低
常见算法:
RSA,DSA