Linux
Linux+shell脚本
前言:断断续续东学一点西学一点,命令也总是搞错,决定系统性梳理一遍,记录常用指令与一些蠢问题,等操作系统学完后再来过一遍,尝试深入理解linux,研究内核。
一、前置知识
1、VMware网络连接三种方式

桥接模式:虚拟机直连外部物理网络,可以互相通讯,但是容易IP冲突,且不够安全
NAT模式:虚拟机和主机构建一个专用网络,并通过NAT设备对IP进行转换。虚拟机通过共享主机IP可以访问外部网络,但外部网络无法访问虚拟机。
安全且不冲突。我现在采用的也是这种模式。
仅主机模式:虚拟机只与主机共享一个专用网络,与外部网络无法通信。
疑惑:虚拟机ping主机时能成功,但是主机ping虚拟机时 ”请求超时“ ?
解决:更改了centos的网络配置文件,修改静态IP,且主机中虚拟网卡VMware8的IP地址由自动更换为手动定义,同虚拟机的ip地址在同一网段,同时也关闭了主机防火墙,遂成功。
然后学会了ssh远程登陆。
虽然会用,但是原理还是懵懵懂懂。果然还是要好好等学完计网才能真正理解。
2、虚拟机克隆
可以当作一份文件一样,克隆到别的地方 或者是别人的电脑上。克隆时需关机。
3、虚拟机快照
拍摄快照,便于迅速回到更改前的状态。
疑惑:物理的操作系统例如现在这台电脑上的windows怎么没有这样的快照功能?
GPT:虚拟机快照的灵活性和效率主要得益于虚拟化架构的设计,而物理系统则更依赖于传统的备份和恢复机制。虚拟机是基于虚拟化技术构建的,允许在同一物理硬件上运行多个操作系统实例。虚拟化软件(如VMware)能够直接管理和控制虚拟机的状态,包括创建快照。这些快照记录了虚拟机的完整状态(包括内存、处理器状态和硬盘)。在物理机器上,操作系统直接与硬件交互,而没有中间的虚拟化层。因此,操作系统无法像虚拟化环境那样封装和管理整个系统的状态。
思考:总是就是,虚拟机毕竟是个软件,因为全部东西都是这个软件模拟出来的,所以它也可以掌控一切。但是物理操作系统就不一样且更复杂,所以没有快照功能。
4、安装vmtools
疑惑:奇怪,我明明没有去安装,且输入查询服务状态等命令时,也显示找不到对应服务,但是我的文件可以直接在主机和虚拟机之间拖拽,也可以复制粘贴,是否说明我是可以有这个功能?暂且不搞,往后面看看再说。
疑惑2.0:为什么我“未能挂起虚拟机”?记得解决这个问题。
5、目录结构
/:Root Directory 所有文件和目录的起点(房门)
/usr:User System Resources存放用户程序和数据的地方 类似于program files(公共图书馆)
/etc:Etcetera存放系统配置文件的地方(规划图和规则手册)
/boot:Boot Loader Files存放启动linux时使用的一些核心文件 包括一些连接文件及镜像文件(启动汽车的钥匙和仪表盘)
/dev:Device Files存放设备文件 代表系统中的硬件设备 如硬盘 终端等 类似于Windows的设备管理器(电器控制面板)
/var:Variable Data存放可变数据(如日志文件、邮件等)的地方(仓库)
/mnt:Mount Directory用于临时挂载文件系统的地方 通常用于管理员手动挂载文件系统(临时存放区)
/bin:Binary Executables 存放系统启动和运行时需要的基本命令和工具 例如 ls, cp (厨房里的常用工具)
/sbin:System Binary Executables存放系统管理命令的地方 这些命令通常只供管理员使用(专业工具房)
/home:Home Directories存放用户个人文件的地方 每个用户都有自己的子目录(居民区)
/lib:Library Files存放系统库文件 这些文件是运行程序时所需的共享库(工具库)
/media:Media Mount Points挂载可移动媒体的地方 比如 USB 驱动器和光盘(停车场)
/opt:Optional Application Software用于安装附加软件包的地方 通常是第三方软件(购物中心)
/proc:Process Information虚拟文件系统 提供有关内核和进程的信息(实时检测仪)
/srv:Service Data存放服务数据的地方 供系统提供特定服务时使用(服务中心)
/root:Root User's Home DirectoryRoot超级用户(root 用户)的主目录(主人房间)
/tmp:Temporary Files存放临时文件的地方(临时工作台)
二、Linux实操
1、远程登陆/文件传输
2、VIM
MIT - Missing-Semester略有听讲,有些基础。这个课也是听一半丢一半。抽时间全听了。
vim三个状态切换,基本指令会使用,不过掌握得还不够熟练,不够深刻。
这个命令就不记录了,用熟即可。
疑惑:为什么物理windows系统安装软件等要从官网上下载压缩包,但是linux只需要短短几行命令就搞定了?
GPT:在物理的 Windows 系统中,安装 JDK 需要下载和运行安装程序,这是因为 Windows 的软件管理方式与 Linux 有很大不同。而在 Linux 上,借助强大的包管理工具,用户可以通过简单的命令快速安装软件,自动处理依赖关系,省去了许多手动操作的步骤。这种设计理念使得 Linux 特别适合开发和服务器环境的使用。
疑惑2.0:具体是怎么做到的?我要去学好操作系统 细细阅读linux的源码,体会它的强大
3、软件包管理
RPM:
rpm -qa查询所安装的所有rpm软件包
(rpm -qa | grep firefox过滤一下)rpm -e xxx卸载软件包rpm -e --nodeps xxx卸载软件包时不检查依赖(危险)rpm -ivh xxx安装软件包(同时显示详细信息及进度条)
YUM:(类似于maven)
基于RPM包管理,能够从指定服务器自动下载RPM包并且安装,可以自动处理依赖性关系,并一次安装所有依赖的软件包
yum -y xxx安装(对自动所有提问回答yes 指定xxx参数)
- 修改默认的系统YUM源(国外网速慢 可改为国内镜像网站)
4、关机/重启/用户登陆注销
shutdown
``shutdown -h now:表示立即关机shutdown -h 1:表示1分钟后关机(后悔还可-c立即停止)shutdown -r now`:立即重启halt关机reboot重启系统sync把内存的数据同步到磁盘上
(当关机或者重启时,都应该先执行一下sync,防止数据丢失)
疑惑:为什么要这样做?为什么会丢失?
回答:linux机制是预先读取,延迟写入,所以直接关机等会造成内存还没来得及写入logout注销用户(在图形运行级别无效,在运行级别3有效)
5、指定运行级别(7个级别)
0关机1单用户(找回丢失密码2多用户状态没有网络服务3多用户状态有网络服务(常用)4系统未使用保留给用户5图形界面(常用)6系统重启
6、帮助指令+常用快捷键
man ls详细查看命令help --ls简略查看命令(此形式用于查看外部命令)ctrl+c停止进程ctrl+l清屏tab自动补全(很好用 经常用)
7、文件目录类指令


pwd显示当前工作目录的绝对路径cdcd回到自己的家目录cd -回到当前目录的上一级目录cd ..回到当前目录的上一级目录
(cd ../home同级文件跳跃)
(cd ./hello下级文件跳跃)lsls -a显示当前目录所有的文件和目录(包括隐藏的)ls -l以列表的方式显示文件信息(简化写法ll)mkdir创建目录mkdir -p创建多级目录rmdir删除空目录rm -rf删除非空的目录touch创建空文件(可以一次性创建多个文件 直接vim也可以新建cp拷贝文件到指定目录cp -r递归复制整个文件夹\cp强制覆盖 屏蔽提示rm移除文件或目录(rm ./*删除当前目录所有文件)rm -r递归删除整个文件夹rm -f强制删除不提示mv移动文件与目录或重命名cat只查看文件内容cat -n显示行号more是一个基于VI编辑器的文本过滤器
Space 向下翻一页
Enter 向下翻一行
q 退出 不再显示该文件内容
Ctrl + F 向下滚动一屏
Ctrl + B 返回上一屏
= 输出当前行的行号
:f 输出文件名和当前行的行号less用来分屏查看文件内容 比more更强大 支持各种显示终端echo输出内容到控制台
(与输出重定向等结合echo helloworld >> hello.c)echo -e支持反斜线控制的字符转换>输出重定向(若不存在会创建文件 否则将原来文件覆盖)>>追加(若不存在会创建文件 否则直接追加到文件的尾部)head显示文件的开头部分head -n 5看前面5行内容tail输出文件中尾部的内容(默认10行)tail -n 5看后面5行内容。tail -f实时追踪该文档的所有更新
(ctrl+s暂停追踪ctrl+q继续追踪)ln给文件创建一个软连接(概念有点像指针)
(先进入想连接的文件再输入ln -s /root/info myInfo)rm -rf 软连接名删除软连接
(注意不是rm -rf 软连接名/这会把真实目录内容也给删掉)history查看历史指令
8、时间日期类指令
date显示当前日期和时间date +%Y显示当前年份date +%d显示当前月份date +%Y-%m-%d %H:%M:%S显示年-月-日 时:分:秒date -s设置系统当前时间cal查看日历指令cal [月] [年份]显示某一年或月的日历
9、用户管理类指令
useradd添加新用户useradd -g 组名 用户名添加新用户到某个组passwd设置用户密码id查看用户是否存在cat /etc/passwd查看创建了哪些用户su切换用户sudo设置普通用户具有root权限(非常强大)groupadd新增组groupdel删除组chmod改变文件权限chown改变所有者
10、搜索查找类指令
find从指定目录向下递归的遍历其各个子目录 将满足条件的文件或者目录显示在终端find -name按照指定的文件名查找模式查找文件(find /root -name info)find /root -name "*.txt"查询目录下所有.txt的文件find -user按照指定的用户名查找模式查找文件。find -size按照指定的文件大小查找模式查找文件(大于多少/小于多少/等于多少)locate快速定位文件路径
利用事先建立的系统中所有文件名称及路径的locate数据库实现快速定位给定的文件 速度极快
管理员必须定期更新locate时刻(默认每日更新一次)
在第一次运行之前 须使用updatedb指令创建locate数据库grep过滤查找(将前一个命令的处理结果输出传递给后面命令处理 经常跟管道一起使用)grep -n显示匹配行及行号
(ls | grep .java)
(cat hello.txt | grep yes)
(grep -n hello initial-setup-ks.cfg | wc)
11、压缩解压类指令
gzip压缩为.gz文件 原来文件不保留gunzip解压缩 同样也不保留源文件zipunzipzip -r递归压缩 即压缩目录unzip -d指定解压后的文件的存放目录tar打包指令 最后打包后的文件是.tar.gz的文件-c产生.tar打包文件-v显示详细信息-f指定压缩后的文件名-z打包同时压缩-x解压.tar文件
12、磁盘查看分区类指令
du查看磁盘占用情况df查看磁盘空间使用情况(df -h)lsblk查看设备挂载情况(lsblk -f)mount挂载
umount卸载fdisk分区fdisk -l查看磁盘分区详情fdisk "name"对新增硬盘进行分区操作
13、进程管理类指令
ps查看当前系统进程状态ps aux | grep xxx查看进程的CPU占用率和内存占用率ps -ef | grep xxx查看进程的父进程ID

kill通过进程号杀死进程killall杀死所有同名的进程
(谨慎操作不推荐 否则kill了守护进程与此终端服务后 只能去机房恢复了)pstree查看进程树(父子关系更直观清晰)pstree -p显示进程的PIDpstree -u显示进程的所属用户top实时监控系统进程状态top -i不显示闲置或僵死进程top -p通过指定监控进程ID来仅仅监控某个进程的状态netstat -anp | grep 进程号查看该进程网络信息netstat -nlp | grep 端口号查看网络端口号占用情况
crontab定时任务设置crontab -e编辑crontab定时任务crontab -l查询crontab任务crontab -r删除当前用户所有的crontab任务


三、Shell脚本
1、shell脚本入门(hello world)
1 | !/bin/bash |

第一种方式:bash等工具解析脚本文件(不用赋予可执行权限)
第二种方式:输入绝对/相对路径调用脚本(文件须有可执行权限)
1 | ./hello.sh |
第三种方式:前面加上source或.
1 | source hello.sh |
疑惑:为什么第一种方式不用+x,第二种需要?
回答:第一种相当于在现有的bash进程里又开了一个bash进程,是bash指令,文件当作一个参数传入,执行解析后面脚本文件的命令。而第二种就是当前这个bash去执行shell命令,所以文本要可执行。然后第三种方式与前两种的区别是,前两种在执行脚本时会开启一个子shell进程,一句句执行脚本,但第三种根本不会开子shell进程,没有这个嵌套环境而是在当前一步步执行(好处是避免了子shell中环境变量的在父shell中不可见可能造成的问题)
2、变量
2.1、系统预定义变量
$HOME $PWD $SHELL等等echo $HOME 查看系统变量的值set 显示当前Shell中所有变量
2.2、自定义变量
my_var="hello, world"定义局部变量(=不能有空格)
(默认定义为字符串 例如a=1+5那么a就是1+5这个字符串)export my_var提升为全局变量unset my_var撤销变量readonly my_var=hello只读变量(静态变量)
(相当于常量 不可修改 不可unset撤销)
2.3、特殊变量
$nn为数字 第n个参数$0代表该脚本名称
($2${10}为了防止与$1混淆需要括号)$#获取所有输入参数个数(常用于循环)$*代表命令行所有的参数 把所有参数看成一个整体$@同上,但是把每个参数区分对待$?最后一次执行命令的返回状态(0正确 非0错误)1
2
3
4
5
6
7
8
9
10
11
12!/bin/bash
防止$n被解析为变量所以不用双引号
echo '=================$n=================='
echo script name: $0
echo 1st paramater: $1
echo 2nd paramater: $2
echo '=================$#=================='
echo parameter numbers: $#
echo '=================$*=================='
echo $*
echo '=================$&=================='
echo $@
3、运算符
a=$[3*8+2]1
2
3!/bin/bash
sum=$[$1+$2]
echo sum=$sum
4、条件判断

[ $a = hello ]通过$?的输出作为返回值来判断真假
(注意格式 必须有四个空格)(若里面为空值 返回为1假)
如图,=两边没有空格 于是$a=hello被识别为一个整体,而非一个表达式,所以返回为真[ xxx ] && echo OK || echo notOK多条件判断(类似三元运算符)
(很有趣的用法。前面为真则执行&&后面逻辑,前面为假则执行||后面逻辑 因为两个符号的特性形成这样效果)
5、流程控制
5.1、if判断
单分支
1
2
3
4
5
6!/bin/bash
sum=$[$1+$2]
if [ $sum -eq 3 ]
then
echo "OK"
fi多分支
1
2
3
4
5
6
7
8
9
10
11!/bin/bash
age=$1
if [ $age -lt 18 ]
then
echo "未成年"
elif [ $age -gt 40 ]
then
echo "已中年"
else
echo "很好的牛马"
fi
5.2、case语句
1 | !/bin/bash |
5.3、for循环
1 | !/bin/bash |
用(())即可使用其他语言中常见运算符,如<=。但不推荐
还有第二种遍历方式:(类似于增强for循环)
注意,{{1..100}} 就是语法里1到100的意思,所以{} 在shell的语法中有如此的特殊定义,因此比起其他语言,if和for之类的都不用花括号括起来。
5.4、while循环
1 | !/bin/bash |
6、控制台输入
read读取控制台输入-p指定读取时提示符-t指定读取值时等待时间(秒)(不加这个则一直等待)
7、函数
函数入门:
1 | !/bin/bash |
注意第二行,等号右边将一个字符串赋值给filename,$()是命令替换,相当于调用了系统的date函数,将+%s传参给date,再将返回结果与$1的内容与_log_一起拼接。
函数与脚本本质上是一样的,都是一段代码逻辑的封装。只不过函数更轻量灵活
注意:
- 在调用函数地方之前,先声明函数,因为shell脚本是逐行执行,不会像其它语言那样先编译
- 函数返回值只能通过
$?系统变量获取,可以显示加:return返回,若不加则将最后一条命令运行结果作为返回值。
系统函数:
basename去掉路径前后冗余 保留文件名(相当于字符串剪切)dirname取文件路径的绝对路径名称(与basename相反)1
2
3!/bin/bash
echo script name: $(basename $0 .sh)
echo script path: $(cd $(dirname $0); pwd)
自定义函数:
1 | !/bin/bash |
函数的返回值是一大疑问,因为$? 只能返回0到255的状态码,所以直接用命令替换,将最后一行的结果传至函数外的变量中存储。
8、正则表达式
8.1、常规匹配
cat /passwd | grep antarctica 匹配所有包含antarctica的行
8.2、模糊匹配(特殊字符)
cat /passwd | grep ^a匹配所有以a开头的行cat /passwd | grep bad$匹配所有以bad结尾的行cat /passwd | grep r..t匹配包含例如rootrat的行cat /passwd | grep ^a.*bash$匹配a开头,bad结尾的行(*代表字符出现任意多次)cat /passwd | grep ^a.*var.*bash$匹配a开头,bad结尾,中间有var的行echo "rat24hdsuinsbadfr" | grep r[a,b]t
9、文本处理工具
cut剪切文本cut -d " " -f 1 cut.txt-f列号 提取第几列-d分隔符 按照指定分隔符分割列( 默认是\t)-c按字符进行切割 后加上n表示取第几列
awk更强大的切割工具-F指定输入文件分隔符-v赋值一个用户定义变量
内置变量:FILENAME文件名NR已读的记录数(行号)NF浏览记录的域的个数(切割后列的个数)1
2
3
4[antarctica000@localhost ~]$ cat /etc/passwd | grep ^root | cut -d ":" -f 7
/bin/bash
[antarctica000@localhost ~]$ cat /etc/passwd | awk -F ":" '/^root/ {print $7}'
/bin/bash