Linux

Linux+shell脚本

前言:断断续续东学一点西学一点,命令也总是搞错,决定系统性梳理一遍,记录常用指令与一些蠢问题,等操作系统学完后再来过一遍,尝试深入理解linux,研究内核。

一、前置知识

1、VMware网络连接三种方式

linux_1.1

桥接模式:虚拟机直连外部物理网络,可以互相通讯,但是容易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参数)
    linux_1.1
  • 修改默认的系统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、文件目录类指令

linux_1.1

linux_1.1

  • pwd 显示当前工作目录的绝对路径

  • cd
    cd 回到自己的家目录
    cd - 回到当前目录的上一级目录
    cd .. 回到当前目录的上一级目录
    cd ../home 同级文件跳跃)
    cd ./hello 下级文件跳跃)

  • ls
    ls -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 解压缩 同样也不保留源文件

  • zip

  • unzip

  • zip -r递归压缩 即压缩目录

  • unzip -d指定解压后的文件的存放目录

  • tar 打包指令 最后打包后的文件是.tar.gz的文件
    -c产生.tar打包文件
    -v显示详细信息
    -f指定压缩后的文件名
    -z打包同时压缩
    -x解压.tar文件

12、磁盘查看分区类指令

  • du 查看磁盘占用情况
  • df 查看磁盘空间使用情况(df -h
  • lsblk 查看设备挂载情况(lsblk -f
  • mount 挂载
    linux_1.1
  • umount 卸载
  • fdisk 分区
    fdisk -l 查看磁盘分区详情
    fdisk "name" 对新增硬盘进行分区操作

13、进程管理类指令

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

三、Shell脚本

1、shell脚本入门(hello world)

1
2
#!/bin/bash
echo "hello world"

linux_1.1

第一种方式:bash等工具解析脚本文件(不用赋予可执行权限)
第二种方式:输入绝对/相对路径调用脚本(文件须有可执行权限)

1
./hello.sh

第三种方式:前面加上source.

1
2
source hello.sh
. hello.sh

疑惑:为什么第一种方式不用+x,第二种需要?
回答:第一种相当于在现有的bash进程里又开了一个bash进程,是bash指令,文件当作一个参数传入,执行解析后面脚本文件的命令。而第二种就是当前这个bash去执行shell命令,所以文本要可执行。然后第三种方式与前两种的区别是,前两种在执行脚本时会开启一个子shell进程,一句句执行脚本,但第三种根本不会开子shell进程,没有这个嵌套环境而是在当前一步步执行(好处是避免了子shell中环境变量的在父shell中不可见可能造成的问题)
linux_1.1

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、特殊变量
  • $n n为数字 第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 $@

    linux_1.1

3、运算符

  • a=$[3*8+2]

    1
    2
    3
    #!/bin/bash
    sum=$[$1+$2]
    echo sum=$sum

    linux_1.1

4、条件判断

linux_1.1

  • [ $a = hello ] 通过$? 的输出作为返回值来判断真假
    (注意格式 必须有四个空格)(若里面为空值 返回为1假)
    linux_1.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
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash
id=$1
case $id in
1)
echo "one"
;;
2)
echo "two"
;;
*)
echo "number else"
;;
esac
5.3、for循环
1
2
3
4
5
6
7
#!/bin/bash
num=$1
for (( i=1; i<=$num; i++ ))
do
sum=$[ $sum + $i ]
done
echo $sum

(())即可使用其他语言中常见运算符,如<=。但不推荐

还有第二种遍历方式:(类似于增强for循环)
linux_1.1

注意,{{1..100}} 就是语法里1到100的意思,所以{} 在shell的语法中有如此的特殊定义,因此比起其他语言,if和for之类的都不用花括号括起来。

5.4、while循环
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash
num=$1
a=1
while [ $a -le $num ]
do
sum=$[ $sum + $a ]
a=$[ $a + 1 ]
done
echo $sum

#!/bin/bash
#更人性化写法!
num=$1
a=1
while [ $a -le $num ]
do
let sum+=a
let a++
done
echo $sum

6、控制台输入

  • read 读取控制台输入
    -p 指定读取时提示符
    -t 指定读取值时等待时间(秒)(不加这个则一直等待)

7、函数

函数入门:

1
2
3
#!/bin/bash
filename="$1"_log_$(date +%s)
echo $filename

注意第二行,等号右边将一个字符串赋值给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
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash

function add(){
s=$[$1 + $2]
echo $s
}

read -p "enter num1: " a
read -p "enter num2: " b

sum=$(add $a $b)
echo "a加b的平分: "$[$sum * $sum]

函数的返回值是一大疑问,因为$? 只能返回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 匹配包含例如root rat的行
  • cat /passwd | grep ^a.*bash$ 匹配a开头,bad结尾的行(*代表字符出现任意多次)
  • cat /passwd | grep ^a.*var.*bash$ 匹配a开头,bad结尾,中间有var的行
  • echo "rat24hdsuinsbadfr" | grep r[a,b]t
    linux_1.1

9、文本处理工具

  • cut 剪切文本 cut -d " " -f 1 cut.txt
    -f 列号 提取第几列
    -d 分隔符 按照指定分隔符分割列( 默认是\t
    -c 按字符进行切割 后加上n表示取第几列
    linux_1.1

  • 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