Linux:信号的保存

文章目录

  • 信号相关概念
    • 信号递达
    • 信号未决
    • 信号阻塞
    • 内核中的示意图
  • 信号集的操作函数

前面对于信号的产生中对操作系统有了一个基础的认知,对于一个真正的操作系统来说,进程是由操作系统进行调度的,那操作系统本身也是代码,是由谁进行调度的?实际上是有一个CMOS时钟这样的硬件,通过特定的时钟周期不断地向CPU发送并触发时钟中断,那么在触发时钟中断的时候,实际上操作系统的内部已经绑定好了对应的调度方法,所以在操作系统启动的时候,就会提前把触发的工作做好,在启动之后就会变成一个死循环的软件,这也就解释了为什么在启动了之后,操作系统虽然是软件,但是却不会关机,只有当电脑关机后操作系统才会关机的原因,就是因为它本质上就是一个死循环,所以基于中断,一旦对应的时钟周期到了,就会执行时钟中断对应的方法,也就有了调度的方法,基于这样的进度就可以把进程按照时间的节奏一步一步的走起来

其实换个角度来讲,操作系统其实是一卡一卡的执行的,因为它在执行中间的这个时间间隔就是发送时钟中断的时间间隔,时钟中断的这个时间其实就是提醒操作系统去执行对应的调度方法,同时在中断向量表中还会绑定一些硬件对应的操作方法,所以最后得出的结论是,操作系统实际上是由硬件促使操作系统跑起来的

有了上述的思想认知,再进行对于进程信号产生的回顾,进程的信号产生是由操作系统写入到进程中,相当于是操作系统向进程发送信号,而在前面的认知中知道,进程对于信号的处理也并非是及时处理,而可能会保存到某个位置,在合适的时候进行处理,那么现在接下来的话题就是,这个信号会如何进行存储,存储之后又该如何进行处理呢?

信号相关概念

信号递达

第一个问题是,信号会被记录存储在哪里,结论是会被存储到PCB中的位图中,这个是之前就已经有的结论,每一个进程的PCB中都会有一个用来描述进程接受的信号的位图,借助这个位图就可以获取到该进程收到了什么信号

接下来的问题是关于处理信号及其相关概念:

  1. 实际执行信号的处理动作称为信号递达
  2. 信号从产生到递达之间的状态,称为信号未决
  3. 进程可以选择阻塞某个信号
  4. 被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作
  • 注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作

下面基于这几个名词进行解释,首先解释的信号递达

所谓信号递达,说的是当进程收到一个信号后,它需要在合适的时候处理这个信号,而这里的处理信号这个过程就叫做信号的递达,简单来说可以理解成,已经收到这个信号,并且准备处理这个信号了,这个处理的动作就叫做信号递达

在前面的内容中提到过,对于信号的处理有三种方式,第一种叫做忽略,第二种是默认,第三种是自定义捕捉,这其实就是说信号递达的问题,当信号递达后,也就是说此时信号已经要进行处理了,那么有上述的三种处理方式

给出下面的参考代码

void handler(int signo)
{
    cout << "收到了" << signo << "号信号" << endl;
}

int main()
{
    cout << "pid:" << getpid() << endl;
    signal(2, handler);
    while (true)
        ;
    return 0;
}

此时对进程发送2号信号,那么对应的这个进程就会调用自定义的处理方式,对应的结果也符合预期,这个过程就是一个自定义捕捉的过程

SIG_DFL和SIG_IGN

void handler(int signo)
{
    cout << "收到了" << signo << "号信号" << endl;
}

int main()
{
    cout << "pid:" << getpid() << endl;
    signal(2, handler);
    signal(3, SIG_IGN);
    signal(4, SIG_DFL);
    while (true)
        ;
    return 0;
}

在这里插入图片描述

上面的两个选项也是一种处理方式,可能这里会有疑问,为什么自定义函数的能和宏放到一起呢?signal函数的第二个参数可是函数指针

其实在内部,是通过强转转换而来的,也是把一个宏对应的内容转换成了函数指针类型

在这里插入图片描述
在这当中需要理清的一个逻辑是,在这当中是有三种处理方式,忽略默认自定义捕捉,这个忽略该如何理解?

忽略也算是处理

忽略也算处理,现在进程收到了一个信号,那它该如何处理它呢?答案是不处理,不处理就是忽略了这个信号,所以说忽略本质上也算是三种处理方式中的一种,处理方式就是不管这个信号,忽略它

所以之后对于信号处理的三种方式,默认自定义忽略,这三种处理方式有了一个统一的名字就叫做信号递达,信号处理这个名词也会被信号递达这个概念所代替

信号未决

下面讲述的概念是信号未决,信号未决通俗来讲就是信号从产生到递达这个阶段的状态就叫做信号未决,可以这样理解,就是信号暂时还没有被决定该如何处理,这个就叫做信号未决,就是说信号此时已经有了,但是还没有处理,在这个阶段的状态就叫做信号未决,这也是可以理解的内容,因为在这个时间内进程可能在做更重要的事,还不能对这个信号做出处理,所以此时就要求需要对这个进程有一定的保存能力,在保存信号的方面可以采用一个位图来进行保存普通信号,所以在信号产生到递达之间的状态,就叫做信号未决

换句话说,信号未决就是从产生到递达这样的一个状态,当信号产生的时候就要把它保存起来,递达就要把信号处理掉,但是信号的处理不是立刻处理的,在这个过程中就是说信号是未决的

信号阻塞

这是一个新的概念,叫做阻塞,那如何理解阻塞呢?

阻塞简单来讲就是说某一个信号可以被阻塞,也有一种说法叫做被阻塞的信号可以保持在一个未决的状态中,直到进程解除对于该信号的阻塞才会调用对应的执行动作。阻塞的含义可以理解为,信号产生后会保存到对应的位图中,此时信号所处的状态就是信号未决,信号未决后,如果该信号被阻塞,那么这个信号就会一直保持未决的状态,直到这个信号解除阻塞

忽略和阻塞

忽略是信号处理中的一种,也就是说信号递达中包含忽略这种处理方式,而信号阻塞是导致不能够信号递达的一个原因,这两个概念是不一样的。信号忽略是说,这个信号被忽略了,对于该信号的处理方式是忽略,而信号阻塞是压根不处理这个信号,这个信号一直处于产生到递达这样的一个阶段中,处于未决状态,这两个是截然不同的两个概念,这也是可以理解的

信号是未决的,该信号一定被阻塞?

显然是不对的,信号是未决的,可能是出于阻塞状态,但是也可能是因为这个进程正在做更重要的事,所以它暂时没有被处理,处于未决状态,但是当这个进程做完了当前最重要的事,那么它一定会立刻对信号进行处理,此时就不再是信号未决的状态了

内核中的示意图

在这里插入图片描述
上图表示的是,在进程的PCB中存储的关于信号的结构信息,在PCB中关于信号会维护三张表,分别存储的是信号的阻塞情况,表示有哪些信号被阻塞了,也存储了信号的未决情况,表示有哪些信号此时递达了,但是还没有处理,也存储了信号对应的处理方式,表示信号对应的处理方式是什么,默认忽略或是自定义捕捉

在内核源码中,对于上述这三张表的定义也总结如下,可以看到对应的handler处理方法中存储了对应的函数指针,表示的就是不同信号的处理方式:
在这里插入图片描述
由此,对于信号的存储有了一个更深层次的理解,为什么进程可以识别到信号,本质上来说就是对于几号信号在pending位图中已经存储好了,几号信号,是否阻塞,对应的解决方式,都在三张表中有具体的体现,根据数组的下标就能很轻松的获取到对应的存储情况和处理方式,在操作系统运行的时候,最起码的pending表和handler表是已经存储好的,所以才有上述的这一套逻辑

而对于block表来说,也有一些不同的理解:

那这个block表该如何理解呢?

block表,表示的是对特定信号的屏蔽,也可以说是对一些信号的阻塞,换句话说,这个位图和后面的两个位图是完全一样的位图结构,有了一个信号,就先在pending位图中记录下这个信号已经处于未决状态了,再在合适的时机去到block位图中寻找,如果这个信号没有被阻塞,那么就执行handler表中的方法,如果这个信号被block阻塞了,那么就让这个信号一直处于pending的状态,等block表中什么时候恢复了,再去执行,当然这当中还有边角的问题,比如谁先置1和置0的问题,后续会进行相关的实验

正是因为有了这三张表,所以对于信号的操作其实都是围绕这三张表进行展开的,比如对于PCB来说,这三张表是由操作系统提供的,那么操作系统就会想办法去获取并设置修改block表来表示对于一个或多个信号的屏蔽的目的,也可以比如说是对于pending位图做修改,或是获取pending位图,比如在之前的bash中的kill命令,本质上就是向指定的进程中写入信号,实际上就是在对这个pending表进行的写入工作,而在之前的signal这样的自定义捕捉函数,本质上也是在修改handler对应的表,这也和前面的知识进行了一定的串联

由此可以看出,操作系统提供对应的系统调用,就是对于这三张表的修改过程,但是这还不够,用户该如何去修改?直接深入到内核中去修改位图中比特位的情况,这对于用户来说是一个很大的挑战,同时对于操作系统来说也违背了它设计的初衷,因此操作系统还会提供对应修改位图的方法,提供了一些新的数据类型,用来帮助用户对于这三张表实现一些操作更改等

多信号问题

现在保存的信号用pending位图表示是否收到了这个信号,但是这个进程可能会在很短的时间内同时收到信号,这个时间短到可能不能及时处理这个信号,在相当短的时间内,连续收到了多个同一个信号,pending位图中只能记录一次,换句话说,此时可能发送了10个相同的信号,但是只记录了一次,剩下的九次就相当于直接被操作系统丢弃了,本质上来说是比特位只能是0和1,如果不断的从1变成1,实际上也获得不了什么新的效果,只能保存历史上最近的一次封信,所以在进程解除对于某个信号的阻塞之前,可能这个信号已经被发送了很多次了,只是不能进行获取,不管发送多少次,最终都是一次

因此操作系统允许向进程推送信号多次,但是在递达之前,不管推送多少次,操作系统只看一次,这是由操作系统本身的位图结构决定的,不过这样情况出现的概率不大,其次是也可以用在信号处理内部放一个计数器,来表示如果设定不够就重新再发,这样的处理方式也是可以接受的

不过值得注意的是,这种只记录一次的信号叫做普通信号,而与之对应的还有一个实时信号,实时信号在前面的内容中也有所涉猎,它的实时信号中的实时概念也就体现在在进程的PCB中有一个实时的信号队列,每一个信号就相当于一个结构体对象,那么就用队列的形式来管理这种信号,也就叫做实时信号,但是这里不考虑实时信号,只是对普通信号做出一个基本的理解

信号集的操作函数

下面进行的模块就是对于信号集的操作函数,下面进行一一列举内容:

下图描述的是对于信号的一些函数,根据这些函数来对于信号的操作函数有一个基本的理解

在这里插入图片描述

sigemptyset函数

这个函数的主要作用是对于set所指向的操作集进行一个基本的初始化,简单来说就是把比特位置0,并且这当中不应该有任何有效的信号

sigfillset函数

这个函数的主要作用是把信号集都置为1,表示这当中存储的是有效的信号

sigaddset和sigdelset函数

这两个函数是对于信号的增加和删除

sigismember函数

这个函数是用来查询某个函数是否在当前的pending信号集中,返回值是bool类

sigprocmask函数

在这里插入图片描述
这个函数是用来读取或更改进程的信号屏蔽字,也就是阻塞信号集,而这个后面的参数,一个是用什么方法来传递,后面的两个参数都是对应的信号集,简单来说就是通过参数来覆盖当前的信号集

对于第一个参数来说,它有下面的几种方式进行传递

在这里插入图片描述

SIG_BLOCK

这个操作会把当前信号阻塞集合和set所指向的信号集合取并集,简单来说是把set集合加入到当前的信号阻塞集合中

SIG_SETMASK

这个操作会把当前信号阻塞集合设置为set所指向的信号集合,会把当前集合直接覆盖掉

SIG_UNBLOCK

这个操作是把当前信号阻塞集合与set集合中的信号的补集取交集,简单来说就是把set中的信号进行解除

后面的两个参数值得注意一下,一个是set,一个是oset,这两个参数是有其对应的意义的,第一个set表示的是要传入覆盖的对应的位图是什么样的,第二个oset是一个输出型参数,它保存的是当前位图的情况,所以本质上来说可以理解成是一个保存了前面位图的参数,这样可以方便后续进行恢复等等操作,具体的后续进行使用

代码实践

下面用代码实践来表示

第一个要完成的动作是把2号信号加到信号屏蔽集中,现在有一个问题是,我设置了加到屏蔽集合中就真的屏蔽了吗?严格意义来说并不是,因为这些内容本质上是在栈上开辟的空间,所以它本质上是在代码区域上,并没有真正设置到操作系统中,所以此时把2号信号添加到集合中也只是在栈上修改了一个变量的信息,这只是语言层面上的设置,而只有通过调用sigprocmask函数后,才能是真正意义上的进行屏蔽的操作,表示的是直接修改了在内核中对于阻塞表的操作,修改了内核的字段,不过,从广义的角度来讲,其实这样的操作就被叫做是加入到了内核中

这里由于是第一次使用,所以要将语言层面和内核层面分开,再怎么说对于位图的修改也只是语言层面上,实际的运用中并没有进行位图的修改,而只有用sigprocmask函数之后,才是进入内核的层面上修改了内核中的相应字段

写出示例代码,如下所示

void handler(int signo)
{
    cout << "收到了" << signo << "号信号" << endl;
}

int main()
{
    signal(2, handler);
    cout << "当前pid:" << getpid() << endl;

    // 1. 屏蔽2号信号
    sigset_t set, oset;
    sigemptyset(&set);
    sigemptyset(&oset);
    sigaddset(&set, 2);
    sigprocmask(SIG_BLOCK, &set, &oset);

    while(true)
        sleep(1);

    return 0;
}

对上述代码进行运行得到如下结果:

在这里插入图片描述
由此可以看出,此时确实对于2号信号进行了屏蔽效果,只有发送其他信号才会有反应

这是由于,经过了sigprocmask之后,此时的2号信号已经存储在了pending表中,那么它此时就不能再被执行了

kill -9

9号信号是最特殊的信号,它本身是不能被屏蔽的,它也被叫做管理员信号,也叫做管理员之光,如果有任何进程出现问题,都可以用kill -9来杀掉,并且保证这个信号不会被屏蔽

sigpending函数

在这里插入图片描述
这个函数的作用也很简单,就是读取当前进程的pending信号集,通过set参数传出,调用成功返回0,失败返回-1

则可以借助这个函数实现下面的代码内容:

void handler(int signo)
{
    cout << "收到了" << signo << "号信号" << endl;
}

void PrintSignal(const sigset_t &set)
{
    for (int i = 31; i >= 1; i--)
    {
        if (sigismember(&set, i))
            cout << "1";
        else
            cout << "0";
    }
    cout << endl;
}

int main()
{
    signal(2, handler);
    cout << "当前pid:" << getpid() << endl;

    // 1. 屏蔽2号信号
    sigset_t set, oset;
    sigemptyset(&set);
    sigemptyset(&oset);
    sigaddset(&set, 2);
    sigprocmask(SIG_BLOCK, &set, &oset);

    // 2. 让进程获取现在的pending
    sigset_t pending;
    while(true)
    {
        sigpending(&pending);
        PrintSignal(pending);

        sleep(1);
    }

    while (true)
        sleep(1);

    return 0;
}

在这里插入图片描述
而想要解除屏蔽也很简单,这个时候就用上了oset的内容:

void handler(int signo)
{
    cout << "收到了" << signo << "号信号" << endl;
}

void PrintSignal(const sigset_t &set)
{
    for (int i = 31; i >= 1; i--)
    {
        if (sigismember(&set, i))
            cout << "1";
        else
            cout << "0";
    }
    cout << endl;
}

int main()
{
    signal(2, handler);
    cout << "当前pid:" << getpid() << endl;

    // 1. 屏蔽2号信号
    sigset_t set, oset;
    sigemptyset(&set);
    sigemptyset(&oset);
    sigaddset(&set, 2);
    sigprocmask(SIG_BLOCK, &set, &oset);

    // 2. 让进程获取现在的pending
    sigset_t pending;
    int cut = 0;
    while (true)
    {
        sigpending(&pending);
        PrintSignal(pending);
        cut++;
        sleep(1);
        if (cut == 5)
        {
            // 3. 解除屏蔽
            cout << "已解除屏蔽" << endl;
            sigprocmask(SIG_SETMASK, &oset, nullptr);
            sigpending(&pending);
            PrintSignal(pending);
            sleep(1);
        }
    }

    while (true)
        sleep(1);

    return 0;
}

在这里插入图片描述
由此,信号的保存也就完成了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/383867.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

算法沉淀——模拟(leetcode真题剖析)

算法沉淀——模拟 01.替换所有的问号02.提莫攻击03.Z字形变换04.外观数列05.数青蛙 模拟算法是一种通过模拟问题的描述或场景来解决问题的算法。这种算法的核心思想是按照问题描述的规则&#xff0c;逐步模拟问题的发展过程&#xff0c;从而得到问题的解决方案。通常&#xff0…

python-自动化篇-终极工具-用GUI自动控制键盘和鼠标-pyautogui

文章目录 用GUI自动控制键盘和鼠标pyautogui 模块鼠标屏幕位置——移动地图——pyautogui.size鼠标位置——自身定位——pyautogui.position()移动鼠标——pyautogui.moveTo拖动鼠标滚动鼠标 键盘按下键盘释放键盘 开始与结束通过注销关闭所有程序 用GUI自动控制键盘和鼠标 在…

InternLM大模型实战-4.XTuner大模型低成本微调实战

文章目录 前言笔记正文XTuner支持模型和数据集 微调原理跟随文档学习快速上手自定义微调准备数据准备配置文件 MS-Agent微调 前言 本文是对于InternLM全链路开源体系系列课程的学习笔记。【XTuner 大模型单卡低成本微调实战】 https://www.bilibili.com/video/BV1yK4y1B75J/?…

python coding with ChatGPT 打卡第20天| 二叉搜索树:搜索、验证、最小绝对差、众数

相关推荐 python coding with ChatGPT 打卡第12天| 二叉树&#xff1a;理论基础 python coding with ChatGPT 打卡第13天| 二叉树的深度优先遍历 python coding with ChatGPT 打卡第14天| 二叉树的广度优先遍历 python coding with ChatGPT 打卡第15天| 二叉树&#xff1a;翻转…

巧用Java 8中的 Function接口,消灭if.else!

点击上方“程序员蜗牛g”&#xff0c;选择“设为星标” 在开发过程中经常会使用if...else...进行判断抛出异常、分支处理等操作。这些if...else...充斥在代码中严重影响了代码代码的美观&#xff0c;这时我们可以利用Java 8的Function接口来消灭if...else...。 if (...){thro…

联想thinkpad-E450双系统升级记

早期笔记本联想thinkpad-E450双系统 大约16年花4000多大洋&#xff0c;买了一台thinkpad-E450屏幕是16寸本&#xff0c;有AMD独立显卡&#xff0c;i5cpu&#xff0c;4G内存。 . 后来加了一个同型号4G内存组成双通道&#xff0c; . 加了一个三星固态500G&#xff0c; . 换了一个…

【更新】企业数字化转型-年度报告175个词频、文本统计

数据说明&#xff1a; 这份数据含数字化转型175个词频、各维度水平&#xff0c;保留2000-2021年数据。参考吴非、赵宸宇两位老师做法&#xff0c;根据上市公司年报文本&#xff0c;整理数字化转型175个词频数据&#xff0c;希望对大家有所帮助。 参考管理世界中吴非&#xff…

车载电子电器架构 —— 电子电气系统控制器开发体系

车载电子电器架构 —— 电子电气系统控制器开发 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费…

【开源】SpringBoot框架开发APK检测管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 开放平台模块2.3 软件档案模块2.4 软件检测模块2.5 软件举报模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 开放平台表3.2.2 软件档案表3.2.3 软件检测表3.2.4 软件举报表 四、系统展示五、核心代…

从互联网的公开信息中,找到属于你的赚钱思路

一、教程描述 人们在互联网上的每一次搜索、每一次关注、每一次点击、每一次点赞、每一次评论、每一次付费&#xff0c;都生成了大量的数据和信息&#xff0c;暴露着人们的真实想法、欲望、恐惧和需求。这些数据和信息&#xff0c;就是我们身边的一座“金矿”&#xff0c;而大…

读千脑智能笔记11_保存人类遗产

1. 智能生物通常能延续多久 1.1. SETI和METI计划的可行性在很大程度上取决于智能生物通常能延续多久 1.1.1. 搜寻地外文明&#xff08;以下简称SETI&#xff09;计划的目标 1.1.1.1. 这是一个力图寻找宇宙其他地方智能生物存在证据的研究项目 1.1.1.2. SETI计划旨在寻找含有…

基于Python的信息加密解密网站设计与实现【源码+论文+演示视频+包运行成功】

博主介绍&#xff1a;✌csdn特邀作者、博客专家、java领域优质创作者、博客之星&#xff0c;擅长Java、微信小程序、Python、Android等技术&#xff0c;专注于Java、Python等技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; …

【数学建模】【2024年】【第40届】【MCM/ICM】【E题 财产保险的可持续性】【解题思路】

一、题目 &#xff08;一&#xff09; 赛题原文 2024 ICM Problem E: Sustainability of Property Insurance Extreme-weather events are becoming a crisis for property owners and insurers. The world has endured “more than $1 trillion in damages from more than …

2024最新苹果电脑mac内存不够用?详细操作方法教程

你是否曾经在使用Mac时感到沮丧&#xff0c;因为那个彩色旋转球不停地在屏幕上转呢&#xff1f;那就是因为你的Mac正在大声呼救&#xff1a;“我的内存不够用了&#xff01;”不用担心&#xff0c;这里有一些绝妙的方法帮助Mac清理内存&#xff0c;让你的电脑恢复流畅运行&…

智慧地球(AI·Earth)社区AIO通用智能服务中心:一站式通用智能(AGI)服务体验

AIO通用智能服务中心 智慧地球&#xff08;AIEarth&#xff09;社区旨在搭建一个将人工智能&#xff08;AI&#xff09;变革性技术带给每个人的服务平台——AIO通用智能服务中心。我们的目标是提供一站式的AGI&#xff08;通用智能&#xff09;服务体验&#xff0c;持续开放最…

windows 查看磁盘空间 treesizefree

https://downloads.jam-software.de/treesize_free/TreeSizeFreeSetup.exe

DRF 分页器的使用

drf提供了三个内置分页器&#xff0c;根据前端需求选择使用。 全局配置 在配置文件中设置全局的分页方式&#xff0c;如&#xff1a; REST_FRAMEWORK {DEFAULT_PAGINATION_CLASS: rest_framework.pagination.PageNumberPagination,PAGE_SIZE: 100 # 每页数目 }也可通过继…

从零开始实现消息队列(二)

从零开始实现消息队列 .核心API交换机类型持久化网络通信Connection和Channel 消息应答模块划分 . 核心API 对于Broker来说,要实现以下核心API,通过这些API来实现消息队列的基本功能. 创建队列(queueDeclare)销毁队列(queueDelete)创建交换机(exchangeDeclare)销毁交换机(exc…

《UE5_C++多人TPS完整教程》学习笔记5 ——《P6 在线子系统(Online Subsystem)》

本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P6 在线子系统&#xff08;Online Subsystem&#xff09;》 的学习笔记&#xff0c;该系列教学视频为 Udemy 课程 《Unreal Engine 5 C Multiplayer Shooter》 的中文字幕翻译版&#xff0c;UP主&#xff08;也是译者&a…

13. 【Linux教程】移动文件和目录

移动文件和目录 前面小节介绍了如何创建文件和目录、删除文件和目录&#xff0c;本小节介绍如何使用 mv 命令移动文件和目录。 1. 移动文件或目录至另外一个目录下 可以使用 mv file_name 路径 这种格式&#xff0c;移动文件至其他目录下&#xff0c;后面跟的路径可以是相对路…