-
一、进程状态 1.1 操作系统学科(运行、阻塞、挂起) 为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态 大多数操作系统都遵循以下原则 1.1.1 运行状态 因为有一个调度器需要确保CPU的资源被合理使用,所以需要维护一个运行队列,他将进程的task_struct结构体连接起来,而被链接起来的进程就会按顺序被调度器调度,此时处于运行队列的这些进程就处于运行态,这说明运行态并不指的是正常运行的进程,而是处在运行队列中并且随时可以被调度的进程! 1.1.2 并发执行和进程切换 调度器将进程放到CPU上去运行,并不代表必须要将进程全部运行完才会被放下来!!因为 (1)进程当中可能会存在一些死循环的进程 (2)调度器要尽量保证公平性,不能让一个进程占用CPU太长时间。 ——>那么什么时候应该把这个进程放下来,就要取决于时间片,当一个进程在超过时间片还没有结束的时候,就要把他放下去然后重新放在新的运行队列的位置。 CPU运行速度是很快的,所以其实我们人所能感受到的,所以在一个时间段内必然所有的进程都会被执行,称之为并发执行。 而大量地把进程从CPU上拿上来在放下去的这个过程,称之为进程切换! 1.1.3 阻塞状态 操作系统管理硬件的过程也是需要先描述再组织,因此不同的硬件设备都需要维护一个阻塞队列,当该硬件没有准备好的时间,该进程只能在阻塞队列中等待。 比如说scanf函数从键盘获取数据,但是如果我们一直不输入的话,这个进程就会被阻塞!! 1.1.4 挂起状态 当操作系统的内部资源严重不足的时候,需要在保证正常运行的前提下想办法把一些内存里的资源置换到磁盘中来节省空间,我们将被置换的进程所处的状态叫做挂起状态。 (1)一般来说,导致内存资源不足的原因是因为存在大量处在阻塞队列的进程 ,所以我们要办法将一些资源置换到磁盘中,但是为了不影响阻塞队列的管理,所以大多数情况下并不止直接将task_struct结构体置换过去,而是将该进程的数据和代码先置换过去,而当执行到该进程的时候,再通过某种方式将其数据和代码置换回来。 (2)其实在我们的电脑中存在一个交换分区,该分区就是专门用来置换一些导致内存溢出的资源 1、挂起状态就是PCB在排队,但是他对应的代码和数据被暂时移到外设中,节省内存空间 。 2、一个进程是否被挂起并不需要让你知道,就跟你把钱存银行里一样,你并不知道自己的钱是被干什么用了,银行并不会告诉你,只是你想要的时候他能及时给到你就好!! 扩展知识:我们的电脑现在大多数使用的都是SSD固态硬盘,磁盘一般只有大公司的后端在使用,虽然比较慢但是便宜且容量更大。 1.2 Linux内核管理进程状态方法 下面的状态在kernel源代码里定义 /* * The task state array is a strange "bitmap" of * reasons to sleep. Thus "running" is zero, and * you can test for combinations of others with * simple bit tests. */ static const char * const task_state_array[] = { "R (running)", /* 0 */ "S (sleeping)", /* 1 */ "D (disk sleep)", /* 2 */ "T (stopped)", /* 4 */ "t (tracing stop)", /* 8 */ "X (dead)", /* 16 */ "Z (zombie)", /* 32 */ }; 1.2.1 进程状态查看 ps aux / ps axj 命令 1.2.2 R状态 R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列中。 1.2.3 S状态 S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠 (interruptible sleep))。 ——>其实就相当于是阻塞状态(因为需要跟硬件保持联系) 为了更好地观察阻塞状态,我们来举个例子: 第一段代码是只有while循环 第二段代码有printf+while循环 问题1:为什么第一种情况是R状态,而第二种情况是S状态呢??? 因为printf需要一直和显示器建立联系,所以有很大概率一直处在等待状态,因为需要等显示器准备好(CPU太快了 所以显示器缓不过来) ,如果不跟硬件建立联系那么该进程的执行速度是非常快的!! 问题2:键盘会因为用户不输入而卡着,那为什么显示器也会卡着呢?? 因为cpu的速度比外设快太多了,所以大多数的进程都在等待,另一方面我们当前的机器是云服务器,用xshell进行链接,所以还会涉及到网络的概念,自然快不了。 同理,其实我们的bash进程也是S状态,因为他在等待你输入指令,你不输入他就会卡住 1.2.4 D状态 D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的 进程通常会等待IO的结束。 区分:S是浅度睡眠(可以被唤醒)、D是深度睡眠 (不相应任何需求)为了能够更好地理解他们的区别,以下会讲述一个故事 比方说我们现在编译了一段代码,需要将1GB的文件写入磁盘中,内存需要跟磁盘建立联系,磁盘在被写入之前需要判断该行为是否可以被执行,比方说现在磁盘中的空间不足1GB,那么这个请求就应该被驳回,这个过程中我们的内存需要先对磁盘说:“我打算写入1GB的内容,你看看可不可以” 磁盘回复:“那你稍等一下,我看看自己的空间是否足够” 当该信息确认后,然后磁盘回复进程:“我当前空间足够,可以执行” 。然后进程才会通过其对应的代码和数据来将1GB写入磁盘。 所以这个过程有发起也有返回,内存像磁盘申请,磁盘完成后将结果返回给内存,但是这个过程是需要等待的!! 假设当前有大量的进程处于阻塞队列,此时内存不够了,因此操作系统需要杀死一部分进程来保证运行 。当系统压力很大时,依靠内存的辗转腾挪解决不了时,操作系统只能想办法杀死他认为不太重要的进程!! 内存在向磁盘发出请求的时候,在磁盘还没回复是否可行的时候该进程就被操作系统杀死了,所以磁盘想要回复的时候发现该进程不在了,所以就懵圈了。当磁盘想要回应的时候却发现那个等待自己的进程没有了,那么现在写入失败了怎么办?我是应该继续尝试呢,还是丢掉呢??此时不同的操作系统有不同的做法。 比如是在银行,某些数据丢失导致损失了几个亿!!这个时候法官 叫来了 操作系统、进程、磁盘 三个人,来这个过程应该是谁的错,第一嫌疑人是操作系统,因为操作系统杀进程了,操作系统说:“请问我是否履行了自己的职责,我是否是在比较极端的情况下去杀进程的,我能做的最大努力就是保证操作系统不挂掉!!如果我有错,那我下次再遇到这种情况??我还做不做了?就算我不杀进程,导致操作系统挂了,他数据该丢还是会丢,还会影响其他进程,这个责任又该谁负责呢??” 法官觉得操作系统说得有道理,于是又把矛头转向了第二嫌疑人磁盘,因为磁盘在写入失败的时候擅自把数据丢失了。磁盘说:“这不怪我,我就是个跑腿的,我在写入的时候就告诉他可能会失败了,所以我让他在那里等我的结果,可是他人不见了,而是丢失是因为我还有其他工作得做,如果我有错的话,那我们是不是得把磁盘所有逻辑都改了???”法官觉得磁盘说的也有代理,于是又把矛头转向了进程,此时进程扑通一声跪了下来说:“我是被杀的,我怎么能有错呢?”所以凡是存在争议很大的地方,大部分都是因为制度设置的不合理。所以法官说,你们都回去吧,我把操作系统改一改——>让一些进行在磁盘写入完毕期间,这个进程不能被任何人杀掉,其实就是不接受任何响应,但是D状态不多见因为如果有很多说明系统已经临近崩溃了!! 1.2.5 T状态 T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可 以通过发送 SIGCONT 信号让进程继续运行。 指令:kill -l 其中9是杀进程,19是暂停进程,18是重启进程 T状态存在的意义:可能是需要等待某种资源,或者是我们单纯不想让该进程运行!! 应用场景就是gdb,当程序运行起来的时候遇到了我打的一个断点,然后就停下来了,这是这个过程就可以被应用于gdb这个进程在控制被调试的这个进程!! 1.2.6 X状态 X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。 1.3 僵尸状态 比如你正在公园跑步,突然看见一个老人走了两步就倒地上了,这时候你叫了120,120发现人已经没救了,于是走了。然后你又叫了110,但是110并不会立马清理现场,因为本质查明真相的原则,可能会需要先带着法医对尸体进行检测然后再确认结果,比如说异常死亡或者是正常死亡(因为家人需要了解情况),然后才会去清理现场。 其实这段已经死亡一直到清理现场之前的这段时间,就相当于是僵尸状态。 回到进程的角度,一个进程在退出的时候并不是立即把所有的资源全部释放,而是要把当前进程的退出信息维持一段时间!!——>因为父进程需要关心子进程!! 为了观察这个现象,我们需要想办法让子进程在中途退出,所以需要exit函数 情况1:当子进程先退出 父进程还在 1 #include<stdio.h> 2 #include<unistd.h> 3 #include<stdlib.h> 4 int main() 5 { 6 pid_t id =fork(); 7 if(id==0) 8 { 9 int cnt=5; 10 while(cnt) 11 { 12 printf("child,pid:%d,ppid:%d,cnt:%d\n",getpid(),getppid(),cnt); 13 --cnt; 14 sleep(1); 15 } 16 exit(0); 17 } 18 else 19 { 20 while(1) 21 { 22 printf("parent,pid:%d,ppid:%d\n",getpid(),getppid()); 23 sleep(1); 24 } 25 } 26 return 0; 27 } 所以只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程保持Z状态,相关的资源尤其是task_struct结构体不能被释放!资源会一直被占用!(defunct是废弃的意思,表示当前进程已经死亡了) 问题1:为什么要存在僵尸状态?? ——>因为他要告诉关心他的进程(父进程),你交代给我的事情我办得怎么样了,所以他一定要等到父进程读取之后才能完全死亡 问题2::那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费(甚至是内存泄漏)? ——>维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话 说,Z状态一直不退出,PCB一直都要维护!!需要占用内存。 情况2:父进程先退出 子进程还在 #include<stdio.h> 2 #include<unistd.h> 3 #include<stdlib.h> 4 int main() 5 { 6 pid_t id =fork(); 7 if(id!=0) 8 { 9 int cnt=5; 10 while(cnt) 11 { 12 printf("parent,pid:%d,ppid:%d,cnt:%d\n",getpid(),getppid(),cnt); 13 --cnt; 14 sleep(1); 15 } 16 exit(0); 17 } 18 else 19 { 20 while(1) 21 { 22 printf("children,pid:%d,ppid:%d\n",getpid(),getppid()); 23 sleep(1); 24 } 25 } 26 return 0; 27 } 说明如果父进程比子进程先一步消亡,那么子进程会变成孤儿进程,他的PPID会变成1 也就是被系统进程给收养。 问题1:为什么要被领养呢?? ——>因为孤儿进程未来也会消亡,也会被释放!! 问题2:ctrl+c为什么无法中止异常进程,他的底层原理是什么?? ——>本质上是在一瞬间父进程会被bash进程回收掉!!所以子进程也在父进程退出的一瞬间被收回掉了!! 所以由于子进程的PPID不是bash进程而是系统进程,所以无法中止 问题3:子进程是bash进程的孙子进程,为什么父进程消亡后不由bash进程回收而是交由系统进程回收??? ——>因为bash做不到,因为孙子进程不是他去创建的!! 他没有这个权限,而系统进程可以做到,因为要将孤儿进程托孤给系统进程 当然不同的操作系统具体的实现方法可能也不同!! 二、Linux具体是怎么维护进程的 你可能会有这样的疑问:Linux内部维护进程主要是采用双链表的形式管理,但是由于其可能有不同的应用场景需求,所以有些时候我们也要把它放到队列、二叉树……中管理,所以为了方便这样的操作,我们的task_struct结构体里面必然需要维护各种各样类型的指针!!那么具体应该如何实现呢?? 首先并不是整个task_struct结构体链接在一起,而是通过单独创建一个node结构体来进行链接,所以其实节点都是指向该结构体中间的位置而不是头部 既然链表链接的并不是头部,那么我们通过节点的链接找到了下一个节点的某个位置,要如何去找到头部呢?? 1、将0强转成task_struct结构体的类型,其实就是假设在0位置都有一个task_struct结构体大小的内存,然后找到他的node节点并取他的地址,由于低地址是0,所以找到node节点的地址就其实就相当于知道了node在task_struct的偏移量 ——> &(task_struct*)0—>node 2、当前找到的位置然后用当前指向的位置(比如start) 减去这个偏移量,就可以找到该结构体的头部。——>start- 3、最后将这个头部的地址强转成task_struct* 就可以拿到整个PCB结构体了 ,就能访问里面的其他数据 总结: ( task_struct*)(start-&(task_struct*)0—>node)——>other 三、进程优先级 3.1 如何理解优先级 问题1:优先级vs权限 ——>权限的意义是这件事我能不能做,而优先级的意义就是对于资源的访问谁先谁后(cpu资源分配的先后顺序,就是指进程的优先权) 问题2:为什么需要有优先级 ——>因为资源是有限的,而进程是多个的,所以进程之间存在竞争关系,优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可能会改善系统性能。 问题3:操作系统是如何做的 ——>操作系统会根据自己的一套规则来尽可能地保证进程的良性竞争,如果进程长时间得不到CPU资源,那么该进程的代码就长时间无法得到推进(进程的饥饿问题),具体需要去给进程维护运行队列,让进程按顺序去执行,但为了防止某些进程运行时间过长,还会有时间片的限制(调度器在工作) 问题4:人为可以调整优先级吗? ——>优先级是可以被人为调整的,我或许可以通过调整优先级让自己的某一个进程可以在同一时间内一直被调度,但是其实Linux并不希望我们有过高的权限,所以他的调整也不是无规则地调整,是带有一定限制的!! 3.2 查看和调整优先级方法 ps –l命令则会类似输出以下几个内容: UID : 代表执行者的身份 PID : 代表这个进程的代号 PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号 PRI :代表这个进程可被执行的优先级,其值越小越早被执行 NI :代表这个进程的nice值 3.2.1 PRI和NI PRI(priotity)即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小进程的优先级别越高 NI(nice)其表示进程可被执行的优先级的修正数值 PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice 这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行 所以,调整进程优先级,在Linux下,就是调整进程nice值 nice其取值范围是-20至19,一共40个级别。 3.2.2 top更改nice值 进入top后按“r”–>输入进程PID–>输入nice值 3.2.3 nice和renice改变优先级 Linux nice和renice命令:改变进程优先级 -扫盲篇_nice设置优先级为什么正数设置不了-CSDN博客 其实这方面的知识并不需要了解很深,因为大多数场景下我们并不会人为地去修改优先级 四、Linux内核的调度算法 1、需要维护两个队列让他们按顺序排队运行 问题1:为什么会有0-99的进程出现呢?? ——>因为这类进程可能是非常重要的!!也就是说无论你当前在运行什么进程,这类进程都会优先被调度(比方说电脑出故障了,发出警报,这个就是无论如何都要优先被警告) 问题2:为什么需要维护两个队列?? ——>因为需要一个队列去运行,但是在运行过程中,后来准备好的进程就会被放到另一个等待队列中,因为这样才能确保按顺序,不然比如我当前运行到后面的时候突然前面又插队了几个进程进来,我又得回头去访问!! 问题3:同等优先级的怎么办? ——>因为维护的是一个指针数组,所以比如说我当前所处的优先级是100,那么下一个优先级100的进来之后就会被链接在后面。本质上是一个开散列!! 2、需要维护一个位图,来确认位置 问题1:如何确定位置呢? ——>因为优先级有各种各样的,比方说在100的位置有2个进程,在133的位置有2个进程,但是我们并不能马上知道这几个地方有进程,而是只能通过遍历数组的方式来一个个查看。最后我们最后当数组遍历到结尾的时候才能确定队列位空 问题2:用位图大O(1) 调度算法优化 ——>只有100-139一共40个级别,我只需要用5个字节一共40个比特位来标记是否存在进程即可,这样我们就可以通过位运算的方法快速找到 队列中存在进程的位置。 最后当位图位0的时候,就说明队列位空了!! 3、需要维护两个指针 因为当运行队列运行完之后就要让等待队列进场,所以最好的方法就是维护两个指针分别指向两个队列,然后当运行队列为空的时候再交换一下指针的指向,让等待队列变成新的运行队列 五、进程重要名词概念 竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级 独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰 并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行(少见,大多数配置的电脑都是只有一个cpu) 并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为 并发(常见) 六、Linux内核进程切换的方法 关于进程切换,我们需要提到并发,并发是基于进程切换基于时间片轮转的调度算法 那么进程具体是如何切换的呢?? 6.1 CPU知识铺垫 问题引入 1、我们的函数返回值是局部变量,但是为什么可以被外部拿到呢?? ——>因为将数据存储在CPU寄存器中带了出去!! 比如return a会转化成move eax 10的指令 2、系统如何得知我们的进程执行到了哪句代码?? ——>因为有程序计数器pc(在PCB内部)以及eip(栈帧寄存器),他们的作用就是记录当前进程正在执行的下一行指令的地址 (其实我们选择语句、循环……的跳转都跟pc有关) 3、寄存器有很多,具体有哪些种类呢??? 通用寄存器:eax、ebx、ecx、edx……(需要什么就做什么的寄存器) 栈帧寄存器:ebp、esp、eip……(ebp和esp是维护栈顶和栈底的,而eip是存储程序计数器的值,表示着进程的下一条指令应该从哪里执行) 状态寄存器:status(记录当前CPU的一些状态) 4、寄存器扮演什么角色呢?? ——>寄存器存储的空间并不大,但是速度快,所以他的作用就是 提高效率,将进程的高频数据放入寄存器中!! 5、如果返回的是内置类型,寄存器可以做到,但如果返回的是一个特别大的对象呢?? ——>因为内置类型很小,所以默认可以被翻译成mov eax ,但如果是一个对象的话,其实本质上来说就是进行了一个拷贝构造,如果是C++11的话可能还会涉及到移动语义,所以本质上来说也是由一个个语句组成的,所以就允许使用多个寄存器来工作。 相当于就是多次mov。 6、寄存器总结 ——>(1)CPU寄存器里面保存的是进程的临时(高频)数据——>进程的上下文信息 (2)由于进程保存的是临时的数据,所以新的数据进入的时候可能会需要覆盖老的数据,因此进程的一些更重要的数据应该被放在离CPU更近的地方!!因为那样更安全更不易丢失!!(比如说重要数据肯定不适合放在通用寄存器上) 6.2 进程切换的本质 下面讲两个故事: 1、你步入大学,但是你有一个参军梦,于是你报名了并且成功被选上了,你很开心于是你就直接去军营了,但是你走之前床铺没有收拾、也没有告诉学校。 于是当你在军营的时候,其实学校并不知道有你去军营了,所以他会给你安排考试,安排宿舍……结果过了一段时间当你回校后,你发现你的宿舍早就换人了,你床铺的东西也都被丢了,然后你本来应该是大一的,却显示大三,挂了三四十门课,即将被勒令退学…… 这个时候你找到了学校说:“我又不是干坏事,而是去当兵,为什么要让我退学??” 学校:“这不怪我啊,你没有打招呼,我根本就不知道你当兵去了”…… 2、还是刚刚的你,但是这次你把自己的床铺收拾好了打包带走,然后你走之前去跟导员报告,将自己的入伍证明交予他查看,然后像学校请求保留学籍,其实就相当于把你的档案给封存了,这个时候学校知道你去当兵了,所以就不会给你安排考试,不会安排宿舍,你的学籍被保留了,你是大二上学期当的兵,你回来时候也是大二上学期…… 通过上面两个故事,我们明白了在我们离开之前一定要做好收尾,这样才能更好地回来,所以对于进程来说,进程从CPU离开的时候,也要将自己的上下文数据保存好然后带走,保存的目的是为了更好地回来(恢复) 问题引入: 问题1:进程在被切换的时候要做什么 ——> (1) 保存上下文 (2)恢复上下文 问题2:pc帮助我们记录下一条指令要运行的位置,那么要保存的数据究竟是存放在哪里呢? ——>存储在PCB中,PCB内部应该有相关的结构体,在寄存器要去执行其他进程之前将相关的数据先存在内部,然后寄存器就可以离开了,当后面寄存器回来的时候就可以帮助进程恢复之前的数据。 ———————————————— 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 原文链接:https://blog.csdn.net/weixin_51142926/article/details/141506586
-
《Linux 中的网络管理:强大而灵活的工具集》在 Linux 系统中,网络管理是一项至关重要的任务。无论是配置网络接口、设置 IP 地址、管理路由,还是监控网络性能,Linux 都提供了丰富的工具和强大的功能。本文将深入探讨 Linux 中的网络管理。一、网络配置文件Linux 中的网络配置主要通过一系列配置文件来实现。其中,最重要的文件包括:/etc/network/interfaces:在许多 Linux 发行版中,这个文件用于配置网络接口。你可以在这里指定 IP 地址、子网掩码、网关等信息。例如:收起plaintext复制auto eth0 iface eth0 inet static address 192.168.1.100 netmask 255.255.255.0 gateway 192.168.1.1/etc/resolv.conf:这个文件用于配置 DNS 服务器。你可以在这里指定一个或多个 DNS 服务器的 IP 地址。例如:收起plaintext复制nameserver 8.8.8.8 nameserver 8.8.4.4二、网络管理工具ifconfig:这是一个用于查看和配置网络接口的工具。你可以使用它来查看网络接口的状态、IP 地址、子网掩码等信息,也可以使用它来临时配置网络接口。例如:收起plaintext复制ifconfig eth0 192.168.1.101 netmask 255.255.255.0 upip:这是一个更强大的网络管理工具,它可以替代ifconfig。ip命令可以用于查看和配置网络接口、路由、邻居缓存等。例如:收起plaintext复制ip addr show eth0 ip link set eth0 up ip route add default via 192.168.1.1route:这个工具用于查看和配置路由表。你可以使用它来查看当前的路由表,也可以使用它来添加、删除或修改路由。例如:收起plaintext复制route -n route add -net 192.168.2.0/24 gw 192.168.1.2netstat:这个工具用于查看网络连接、路由表、接口统计等信息。例如:收起plaintext复制netstat -an netstat -rnmap:这是一个用于网络探测和安全审计的工具。你可以使用它来扫描网络中的主机、端口等信息。例如:收起plaintext复制nmap 192.168.1.0/24 nmap -p 80 192.168.1.100三、网络监控工具iftop:这是一个实时网络流量监控工具。它可以显示网络接口上的实时流量情况,包括上传和下载速度、连接的主机等信息。例如:收起plaintext复制iftop -i eth0nethogs:这个工具可以实时监控每个进程的网络使用情况。它可以帮助你找出哪个进程占用了大量的网络带宽。例如:收起plaintext复制nethogs eth0tcpdump:这是一个强大的网络数据包捕获工具。你可以使用它来捕获网络接口上的数据包,并进行分析。例如:收起plaintext复制tcpdump -i eth0 tcpdump -i eth0 port 80四、网络故障排除当网络出现问题时,Linux 提供了一些工具来帮助你进行故障排除。以下是一些常用的方法:检查网络接口状态:使用ifconfig或ip addr show命令查看网络接口的状态。确保接口已启用,并且有正确的 IP 地址和子网掩码。检查路由表:使用route -n或ip route show命令查看路由表。确保有正确的默认网关和其他路由。检查 DNS 配置:使用cat /etc/resolv.conf命令查看 DNS 服务器的配置。确保有正确的 DNS 服务器 IP 地址。检查网络连接:使用ping命令测试与其他主机的连接。例如,ping 8.8.8.8可以测试与 Google 的公共 DNS 服务器的连接。使用网络监控工具:使用iftop、nethogs或tcpdump等工具来监控网络流量,找出可能的问题。五、总结Linux 中的网络管理提供了丰富的工具和强大的功能,可以满足各种网络管理需求。通过了解网络配置文件、网络管理工具和网络监控工具,你可以更好地管理 Linux 系统中的网络。在进行网络管理时,一定要小心谨慎,确保不会对系统的稳定性和安全性造成影响。如果遇到问题,可以使用网络故障排除工具来找出问题的根源,并及时解决。
-
《Linux 中的 OpenSSH:强大的远程连接工具》在 Linux 系统的管理和使用中,OpenSSH 是一个不可或缺的工具。它为我们提供了安全、可靠的远程连接方式,让我们能够轻松地管理远程服务器。今天,我们就来深入了解一下 Linux 中的 OpenSSH。一、OpenSSH 简介OpenSSH 是一款开源的 SSH(Secure Shell)协议的实现,用于在不安全的网络中提供安全的远程登录和其他网络服务。它使用加密技术来保护通信的安全性,防止数据被窃取或篡改。二、安装 OpenSSH在大多数 Linux 发行版中,OpenSSH 通常是默认安装的。如果你的系统中没有安装 OpenSSH,可以使用包管理器进行安装。例如,在 Ubuntu 系统中,可以使用以下命令安装 OpenSSH:sudo apt-get install openssh-server在安装完成后,OpenSSH 服务会自动启动。三、使用 OpenSSH 进行远程连接远程登录 使用 SSH 客户端可以远程登录到其他 Linux 服务器。在命令行中输入以下命令:ssh username@remote_host其中,username是远程服务器上的用户名,remote_host是远程服务器的 IP 地址或域名。在第一次连接时,系统会提示你确认远程服务器的指纹,输入yes确认后,就可以输入密码进行登录。文件传输 OpenSSH 还提供了文件传输功能,可以使用scp命令在本地和远程服务器之间传输文件。例如,将本地文件local_file传输到远程服务器的remote_directory目录下,可以使用以下命令:scp local_file username@remote_host:remote_directory如果要从远程服务器下载文件,可以使用以下命令:scp username@remote_host:remote_file local_directory端口转发 OpenSSH 还可以进行端口转发,实现通过本地端口访问远程服务器上的服务。例如,将远程服务器上的 80 端口转发到本地的 8080 端口,可以使用以下命令:ssh -L 8080:localhost:80 username@remote_host这样,就可以在本地浏览器中通过访问http://localhost:8080来访问远程服务器上的 Web 服务。四、配置 OpenSSHOpenSSH 可以通过配置文件进行定制化配置。主要的配置文件是/etc/ssh/sshd_config,用于配置 SSH 服务器的行为。以下是一些常见的配置选项:端口号 可以修改默认的 SSH 端口号,增强安全性。在配置文件中找到Port选项,将其修改为你想要的端口号。密码认证 可以禁用密码认证,使用密钥认证来提高安全性。在配置文件中找到PasswordAuthentication选项,将其设置为no。密钥认证 使用密钥认证可以避免输入密码,提高登录的便利性和安全性。首先,在本地生成密钥对,可以使用以下命令:ssh-keygen然后,将公钥复制到远程服务器上,可以使用以下命令:ssh-copy-id username@remote_host五、安全注意事项定期更新 OpenSSH 为了确保安全性,建议定期更新 OpenSSH 到最新版本。可以使用包管理器进行更新。加强密码安全 如果使用密码认证,建议使用强密码,并定期更换密码。限制访问 可以通过配置防火墙或使用AllowUsers和DenyUsers选项来限制哪些用户可以远程登录到服务器。六、总结OpenSSH 是 Linux 系统中非常强大的远程连接工具,它提供了安全、可靠的远程登录和文件传输功能。通过合理配置 OpenSSH,可以提高服务器的安全性和管理效率。在使用 OpenSSH 时,一定要注意安全问题,确保服务器的安全稳定运行。
-
《》在使用 Linux 系统的过程中,随着数据的不断增长,可能会遇到硬盘空间不足的情况。这时,我们就需要对硬盘进行扩容。本文将详细介绍 Linux 硬盘扩容的步骤。一、前期准备确认硬盘类型 首先,你需要确定你的硬盘是物理硬盘还是逻辑卷。如果是物理硬盘,可以直接进行扩容操作。如果是逻辑卷,则需要通过逻辑卷管理工具进行扩容。备份重要数据 在进行硬盘扩容之前,一定要备份重要数据。虽然扩容过程中数据丢失的可能性较小,但为了以防万一,备份是非常必要的。二、物理硬盘扩容步骤关闭系统 如果要对物理硬盘进行扩容,需要先关闭系统。确保在关机状态下进行硬盘的物理连接操作。连接新硬盘 将新的硬盘连接到系统中。可以通过 SATA、SAS 或其他接口连接硬盘。确保连接正确并牢固。启动系统 重新启动系统,让系统识别新连接的硬盘。查看硬盘信息 使用命令fdisk -l或lsblk查看系统中所有硬盘的信息,确认新硬盘已经被识别。分区新硬盘 使用分区工具(如 fdisk、parted 等)对新硬盘进行分区。可以根据自己的需求创建一个或多个分区。格式化分区 选择合适的文件系统(如 ext4、xfs 等)对分区进行格式化。可以使用命令mkfs.<文件系统类型> /dev/<分区名称>进行格式化。挂载分区 创建一个挂载点(如/mnt/new_disk),然后使用命令mount /dev/<分区名称> /mnt/new_disk将新分区挂载到系统中。迁移数据或扩展现有分区 如果需要将现有数据迁移到新分区,可以使用文件复制工具(如 cp、rsync 等)进行数据迁移。如果要扩展现有分区,可以使用逻辑卷管理工具(如 LVM)进行操作。三、逻辑卷扩容步骤确认逻辑卷管理工具 Linux 系统中常用的逻辑卷管理工具是 LVM(Logical Volume Manager)。确保你的系统中安装了 LVM 工具。查看逻辑卷信息 使用命令lvdisplay查看系统中现有逻辑卷的信息,包括逻辑卷名称、大小、挂载点等。查看物理卷信息 使用命令pvdisplay查看系统中现有物理卷的信息,包括物理卷名称、大小、状态等。查看卷组信息 使用命令vgdisplay查看系统中现有卷组的信息,包括卷组名称、大小、物理卷数量等。添加新硬盘 如果要扩展逻辑卷,需要先添加新的物理硬盘。连接新硬盘后,使用命令pvcreate /dev/<新硬盘名称>将新硬盘创建为物理卷。扩展卷组 使用命令vgextend <卷组名称> /dev/<新硬盘名称>将新的物理卷添加到现有卷组中,扩展卷组的大小。扩展逻辑卷 使用命令lvextend -L +<新大小> /dev/<逻辑卷名称>扩展逻辑卷的大小。其中,<新大小>可以是具体的容量值(如 10G),也可以是百分比(如 +20%)。通知文件系统扩容 对于不同的文件系统,通知文件系统扩容的方法也不同。例如,对于 ext4 文件系统,可以使用命令resize2fs /dev/<逻辑卷名称>;对于 xfs 文件系统,可以使用命令xfs_growfs /mount_point。四、总结Linux 硬盘扩容可以通过物理硬盘扩容和逻辑卷扩容两种方式实现。在进行扩容操作之前,一定要备份重要数据,并根据自己的需求选择合适的扩容方式。如果对操作过程不熟悉,可以先在测试环境中进行练习,以确保操作的正确性和安全性。
-
《Linux 主机启动过程管理详解》在 Linux 系统中,了解主机的启动过程对于系统管理和故障排除至关重要。本文将深入探讨 Linux 主机启动过程的各个阶段以及如何进行有效的管理。一、Linux 主机启动过程概述Linux 主机的启动过程可以大致分为以下几个阶段:BIOS/UEFI 初始化当计算机启动时,BIOS(基本输入 / 输出系统)或 UEFI(统一可扩展固件接口)首先被激活。它们负责硬件的初始化,如检测内存、硬盘、显卡等设备,并加载引导程序。引导加载程序引导加载程序(如 GRUB)负责加载 Linux 内核。它通常位于硬盘的主引导记录(MBR)或 EFI 系统分区中。引导加载程序会根据配置文件选择要启动的内核版本和启动参数。内核初始化内核被加载后,开始进行初始化。这包括检测硬件设备、加载驱动程序、建立内存管理系统、启动内核线程等。内核还会挂载根文件系统,为后续的系统启动做准备。系统初始化一旦内核初始化完成,系统会启动第一个进程(通常是 init 或 systemd)。这个进程负责启动其他系统服务和用户空间程序。系统初始化过程包括设置主机名、网络配置、启动守护进程等。用户登录最后,系统会显示登录提示符,等待用户输入用户名和密码进行登录。用户登录后,可以开始使用系统。二、管理 Linux 主机启动过程调整引导加载程序配置引导加载程序的配置文件(如 GRUB 的/etc/default/grub和/boot/grub/grub.cfg)可以用于调整启动参数。例如,可以设置默认启动的内核版本、添加内核参数、调整启动顺序等。在修改引导加载程序配置后,通常需要运行update-grub命令来更新引导配置。内核参数调整内核参数可以在引导加载程序中传递,也可以在系统运行时通过/proc/sys目录或sysctl命令进行调整。内核参数可以用于优化系统性能、解决特定的硬件问题或启用特定的功能。例如,可以通过设置vm.swappiness参数来调整系统对交换空间的使用策略,或者通过设置net.ipv4.ip_forward参数来启用 IP 转发功能。系统服务管理在系统初始化阶段,init 或 systemd 会启动各种系统服务。可以通过修改服务的启动脚本或使用服务管理工具(如systemctl或service)来控制服务的启动和停止。可以根据系统的需求,禁用不必要的服务,以减少系统资源的占用和提高系统的启动速度。故障排除启动问题如果 Linux 主机在启动过程中出现问题,可以通过查看启动日志(如/var/log/dmesg、/var/log/messages等)来获取有关问题的信息。还可以使用单用户模式或救援模式来修复启动问题。在单用户模式下,可以进行一些基本的系统修复操作,如修复文件系统错误、恢复丢失的密码等。救援模式通常提供了更多的工具和选项,用于解决更复杂的启动问题。三、总结Linux 主机的启动过程是一个复杂的系统初始化过程,涉及到硬件检测、内核加载、系统服务启动等多个阶段。通过了解启动过程的各个阶段以及如何进行有效的管理,可以更好地维护和优化 Linux 系统。在遇到启动问题时,可以通过调整引导加载程序配置、内核参数和系统服务管理等方法来进行故障排除,确保系统能够正常启动和运行。
-
在 Linux 系统中,有一个非常强大的工具叫做 crontab,它可以让我们轻松地实现定时任务的设置和管理。无论是定期备份数据、清理临时文件,还是执行其他自动化任务,crontab 都能发挥巨大的作用。一、什么是 CrontabCrontab 是一个用于在 Linux 系统中设置定时任务的工具。它允许用户指定在特定的时间间隔或特定的时间点执行特定的命令或脚本。Crontab 基于 cron 守护进程运行,该守护进程会在系统启动时自动启动,并定期检查 crontab 文件以确定是否有需要执行的任务。二、Crontab 的基本语法Crontab 的语法相对简单,但需要一些时间来熟悉。一个典型的 crontab 条目由五个时间字段和一个要执行的命令组成。这五个时间字段分别表示分钟、小时、日、月和星期几。例如,以下是一个简单的 crontab 条目:收起plaintext复制* * * * * /path/to/command这个条目表示每分钟执行一次/path/to/command命令。每个时间字段可以使用以下几种格式:具体的值:例如,“5” 表示在第 5 分钟执行任务。范围:例如,“1-5” 表示在第 1 分钟到第 5 分钟之间执行任务。步长:例如,“*/5” 表示每隔 5 分钟执行任务。列表:例如,“1,3,5” 表示在第 1 分钟、第 3 分钟和第 5 分钟执行任务。三、设置 Crontab 任务编辑 Crontab 文件 可以使用crontab -e命令来编辑当前用户的 crontab 文件。这个命令会打开一个文本编辑器,你可以在其中添加、修改或删除 crontab 条目。添加任务 要添加一个新的任务,只需在 crontab 文件中添加一行新的条目。例如,如果你想每天凌晨 2 点执行一个备份脚本,可以添加以下条目:收起plaintext复制0 2 * * * /path/to/backup_script.sh保存和退出 编辑完成后,保存文件并退出编辑器。Cron 守护进程会自动读取新的 crontab 文件,并在指定的时间执行任务。四、查看和管理 Crontab 任务查看当前用户的 Crontab 任务 可以使用crontab -l命令来查看当前用户的 crontab 任务列表。删除任务 要删除一个任务,可以再次使用crontab -e命令,然后删除相应的条目。保存文件后,Cron 守护进程会自动更新任务列表。查看 Crontab 日志 Cron 守护进程会将任务的执行情况记录在系统日志中。你可以使用tail -f /var/log/syslog命令来实时查看系统日志,以了解 crontab 任务的执行情况。五、注意事项命令路径 在 crontab 条目中指定的命令或脚本的路径必须是绝对路径。如果使用相对路径,Cron 守护进程可能无法找到该命令或脚本。环境变量 Cron 守护进程在执行任务时使用的环境变量与用户登录时的环境变量不同。因此,在 crontab 条目中执行的命令或脚本可能需要显式地设置一些环境变量,以确保它们能够正常运行。权限问题 确保你有足够的权限来执行 crontab 条目中指定的命令或脚本。如果需要以其他用户的身份执行任务,可以使用sudo命令或设置适当的权限。六、实际应用场景系统维护任务 定期清理临时文件、备份重要数据、检查系统磁盘空间等。自动化任务 例如,每天定时发送邮件报告、自动更新软件等。监控任务 定期检查系统状态、网络连接等,并在出现问题时发送警报。
-
在 Linux 系统的安全领域中,SELinux(Security-Enhanced Linux)是一个强大的工具,它为系统提供了更高级别的安全保障。今天,我们就来深入探讨一下 SELinux 的用法。一、SELinux 简介SELinux 是一种基于强制访问控制(MAC)的安全机制,它通过对系统中的主体(如用户、进程)和客体(如文件、目录、端口等)进行严格的访问控制,来增强系统的安全性。与传统的自主访问控制(DAC)不同,SELinux 不依赖于用户的主观判断,而是根据预设的安全策略来决定主体对客体的访问权限。二、SELinux 的工作模式SELinux 有三种工作模式:Enforcing(强制模式):在这种模式下,SELinux 会严格按照安全策略进行访问控制。如果主体对客体的访问违反了安全策略,访问将被拒绝。Permissive(宽容模式):在这种模式下,SELinux 会记录违反安全策略的访问行为,但不会阻止这些访问。这对于调试和了解系统的安全状况非常有用。Disabled(禁用模式):在这种模式下,SELinux 被完全关闭,系统将恢复到传统的 DAC 访问控制模式。三、SELinux 的用法查看 SELinux 状态 可以使用sestatus命令来查看当前系统中 SELinux 的状态。该命令会显示 SELinux 的工作模式、策略类型等信息。切换 SELinux 工作模式 可以通过修改/etc/selinux/config文件中的SELINUX=参数来切换 SELinux 的工作模式。例如,将SELINUX=enforcing改为SELINUX=permissive可以将 SELinux 从强制模式切换到宽容模式。修改完后,需要重新启动系统才能使更改生效。管理 SELinux 策略 SELinux 的策略决定了主体对客体的访问权限。可以使用semanage命令来管理 SELinux 策略。例如,可以使用semanage port -a -t http_port_t -p tcp 8080命令来将端口 8080 标记为 HTTP 端口,允许 HTTP 服务使用该端口。处理 SELinux 违规 如果在系统运行过程中出现了 SELinux 违规行为,可以使用audit2allow命令来分析审计日志,并生成相应的策略模块,以允许特定的访问行为。例如,如果某个进程无法访问某个文件,可以使用audit2allow -a命令来分析审计日志,并生成相应的策略模块,然后使用semodule -i <module_name>.pp命令来安装该策略模块。四、SELinux 的优势增强系统安全性 SELinux 通过严格的访问控制,可以有效地防止恶意软件和攻击者对系统的攻击。它可以限制进程的权限,防止进程对系统资源的非法访问,从而提高系统的安全性。提高系统稳定性 SELinux 可以防止进程之间的非法交互,从而减少系统崩溃和错误的发生。它可以确保系统中的各个组件按照预设的安全策略进行交互,提高系统的稳定性。便于系统管理 SELinux 的策略可以集中管理,管理员可以通过修改策略文件来控制整个系统的安全策略。这使得系统管理更加方便和高效。
-
1.背景生产环境进行了漏洞扫描检测出sshd服务的版本漏洞(CVE-2024-6387),给出的解决方案是升级最新版本的sshd服务即最新版本9.8,升级sshd服务需要依赖openssl,在升级的同时也将openssl版本进行了升级,升级的openssl版本是openssl-1.1.1l。使用的操作系统是银河麒麟V10SP2 arm64。2.过程升级完成后ssh服务测试正常使用没有问题但是curl和yum命令执行时分别出现了如下报错curl: relocation error: /lib64/libcurl.so.4: symbol SSLv3_client_method version OPENSSL_1_1_0 not defined in file libssl.so.1.1 with link time referenc根据报错分析是升级openssl的版本和现有的版本的libcurl.so.4的文件不兼容导致,因此也查询了资料进行了修复,但是都没有效果,最终决定重新编译安装curl命令试试。编译安装curl命令如下step1:下载curl源码包1wget https://curl.se/download/curl-8.8.0.tar.gzstep2:解压1tar xf curl-8.8.0.tar.gzstep3:编译(使用刚才升级的openssl作为依赖)12cd curl-8.8.0/./configure --prefix=/usr/src --with-ssl=/usr/local/sslstep4:安装1make && make install编译安装完成后会在/usr/src/目录下生成4个目录/usr/src/{bin,include,lib,share},curl命令的可执行文件在bin目录下,我们可以进行测试一下:测试curl命令可以正常使用,但是yum命令还不行此时我们可以查看新编译安装的curl命令的lib目录/usr/src/lib目录下有libcurl.so.4软连接的文件我们将原机器的libcurl.so.4文件进行备份,用新编译的文件进行一个替换操作12345[root@ths01 ~]# ls -l /lib64/libcurl.so.4lrwxrwxrwx 1 root root 16 Jun 8 2020 /lib64/libcurl.so.4 -> libcurl.so.4.6.0[root@ths01 ~]# mv /lib64/libcurl.so.4.6.0 /lib64/libcurl.so.4.6.0_bak[root@ths01 ~]# chmod +x libcurl.so.4.8.0[root@ths01 ~]# mv libcurl.so.4.8.0 /lib64/libcurl.so.4.6.0此时们再次使用curl和yum命令就会恢复正常
-
CodeArts IDE支持Linux系统不?我看申请了云主机是ubuntu,预装了CodeArts IDE for JAVA不知道哪里有CodeArts IDE的Linux安装包下载?
-
一、缓冲区 1.1 概念 要理解什么是缓冲区,先看这段代码 #include <stdio.h> #include <string.h> #include <unistd.h> int main() { const char *fstr = "fwrite\n"; const char *str = "write\n"; printf("printf\n"); fprintf(stdout, "fprintf\n"); fwrite(fstr, strlen(fstr), 1, stdout); write(1, str, strlen(str)); fork(); return 0; } 执行程序,会向终端打印四行内容 但是如果我们把程序输出的内容重定向到一个普通文件中,会打印多少行呢? 此时变成了7行内容,其中printf、fprintf和fwrite打印了两次,为什么? 我们可以看到,在程序的最后创建了一个子进程,所以肯定是因为子进程所以才会重复打印 并且重复打印的接口都是库函数,而系统调用接口write并没有打印两次 在前面的学习中,我们已经初步认识了什么是缓冲区,这里简单回顾一下 实际上我们在对一个文件进行写入时并不是直接写入到文件中的,而是先写入到缓冲区,缓冲区再根据不同的方式将其内容刷新到文件中 缓冲区有三种刷新方式: 无缓冲,即一进行写入就对缓冲区进行刷新,一个一个字符写入 行缓冲,遇到\n才对缓冲区进行刷新,一行一行写入 全缓冲,缓冲区满了才进行刷新,一堆一堆写入 一般我们在向显示器文件进行写入时采用的策略是行缓冲,即遇到\n就打印一行;而对于普通文件系统则采用全缓冲策略。缓冲区的存在能够减少消耗,提高效率 而我们还知道,子进程虽然会继承父进程的代码和数据,不过一旦一方修改了数据,就会发生写时拷贝 而缓冲区不同的刷新方式配合上写时拷贝,你是否已经知道为什么会发生重复打印了呢? 没错,因为向显示器文件中打印的时候采用行缓冲策略,所以缓冲区中不会有内容堆积,遇到\n就刷新一次缓冲区 所以在最后创建子进程时父进程的缓冲区空空如也,所以子进程的缓冲区也是空的 但是,如果重定向到了普通文件,此时就要采用全缓冲策略,所有的内容都堆积在缓冲区中 子进程创建时继承了父进程包含一大堆内容的缓冲区,而父进程在退出时刷新缓冲区的时候发生写时拷贝,不会影响到子进程的缓冲区,此时子进程再进行写入,就导致部分内容被写入了两次 但是为什么write不会重复写呢? 1.2 用户缓冲区和内核缓冲区 我们观察到,在向普通文件中打印时,库函数被打印了两次,而只有系统调用接口write打印了一次 为什么? 实际上C语言中的库函数写入的缓冲区是C语言提供的用户级缓冲区,而write这种系统调用接口直接写入的是内核的缓冲区 父子进程间的写时拷贝局限于用户态,不会影响到内核缓冲区 C语言的部分文件操作接口封装了系统调用接口write,库函数首先将内容写入到用户级缓冲区,然后根据不同的刷新方式调用write将内容写入到内核的缓冲区 我们再来看一段代码 #include <stdio.h> #include <string.h> #include <unistd.h> int main() { const char *fstr = "fwrite\n"; const char *str = "write\n"; printf("printf\n"); fprintf(stdout, "fprintf\n"); fwrite(fstr, strlen(fstr), 1, stdout); write(1, str, strlen(str)); close(1); // 关闭标准输出流 return 0; } 将打印的内容重定向到普通文件,此时发现只有write被打印了 这也是因为close关闭文件描述符时只会把内核缓冲区中的内容刷新到文件中,所以库函数向用户缓冲区写入的内容采用全缓冲还停留在用户缓冲区内,而write向内核缓冲区写入的内容被刷新到了文件中 C语言提供的用户缓冲区在哪呢?前面我们见过C语言提供的FILE结构体,存放了文件描述符等内容,其内部还有对应文件的缓冲区字段和维护信息 语言都属于用户层,C语言提供的FILE结构体自然也属于用户,所以其内部的缓冲区属于用户级缓冲区 二、磁盘的结构 磁盘是计算机主要的存储介质,可以存储大量的二进制数据,并且断电后也能保持数据不丢失。早期计算机使用的磁盘是软磁盘(Floppy Disk,简称软盘),如今常用的磁盘是硬磁盘(Hard disk,简称硬盘) 文件在没被打开的时候,是以二进制形式存储在硬盘中的,而硬盘又是如何存储这些二进制数据的呢? 机械硬盘的内部结构: 一个硬盘里可能堆叠了多张盘片,盘片的每一面都有一个磁头,这些所有的磁头都是连在同一个磁头臂上的,所以只能共同移动。磁头和盘面不接触 盘片表面涂有磁性物质,通过输入不同的电流方向,来改变不同部位的磁性,从而就能区分出0和1 而一个盘面又分为许多不同半径的同心圆,每个圆环是一个磁道,磁道的内部又分为许多的扇区 每个扇区能够存储的内容大小一样,其中,最内侧磁道上的扇区面积最小,因此数据密度最大 每张盘片的大小相同,而在不同的盘片中处于相同位置(同样半径)的磁道组成了柱面 磁盘被访问的最基本单元是扇区,一个扇区一般是512字节 因此,我们可以把磁盘看作由无数个扇区构成的存储介质 既然有了扇区,要把数据保存到磁盘中或取出数据,首先要解决的问题是:如何定位一个扇区 要定位一个扇区,我们得先知道要保存到哪一面(即哪个磁头),和哪一个磁道(柱面) 因此产生了CHS寻址方式:依据柱面(磁道)、磁头、扇区来查找数据位置 首先定位对应数据所在的盘面,移动对应盘面的磁头 ;磁头臂带动磁头在盘面上移动,就是定位磁道的过程;而主轴带动盘片旋转,则是定位扇区的过程 如果我们像磁带一样把磁盘的所有盘面展开成一个线性的结构,那么整个磁盘就像是一个由无数扇区构成的数组,每个扇区就有自己独立的编号,我们称为LBA地址 现在我们可以把磁盘视为一个数组,只需要知道每个盘面有多少个扇区,每个磁道有多少个扇区,我们就可以通过某个扇区的下标找到其对应的磁头、磁道、扇区了 例如我们假设一个盘面有20000个磁道,一个磁道有400个扇区 通过计算,我们就可以把LBA地址转化为CHS地址了 三、文件系统 3.1 初识“块”和inode 一个文件如果为空,那么它存储在磁盘中是否不会占用空间呢?答案是否 文件不单单包含文件内容,还包含文件属性。文件的内容由一个个数据块存储,而文件的属性则需要一个名为inode的结构保存 数据块(block)的大小通常为4KB,即8个扇区组成一个块。块是文件存取的最小单位,即操作系统在读取硬盘时不会一个个扇区存取,这样影响效率,而是最少取一个块。文件的属性则由名为inode的结构存储,其内部存放了inode编号、文件类型、文件权限等属性 每个数据块也有编号,因为文件的内容存储在许多的数据块中,inode中一定会有一个数组存储该文件的所有块编号。但是如果块很多,一个数组大小不一定存的下这么多编号 为了让数组存下整个文件的所有块编号,数组后几个位置存在多级索引,具体实现为其编号对应的块中存储的不是文件内容,而是其他块的编号。在逻辑上体现为一颗多叉树的结构 需要注意的是,inode中的属性不包含文件名,每个inode都有自己唯一的编号,系统中标识一个文件只看inode编号 我们也可以通过 ls -li 命令来查看一个文件的inode编号: 除此之外,我们还可以通过stat命令来获取更详细的文件属性信息: 3.2 磁盘分区和文件系统 我们发现,即使我们的电脑里只有一块硬盘,但也能分出很多个区,即我们电脑中的C盘、D盘等,并且我们还可以自己设置这些分区的大小 但是这些分区还是太大了,不便于管理,因此我们再将一个分区划分为多个块组 在Linux的ext2文件系统中,Boot Block(引导块)位于分区的开头,占用1024字节,用于存放开机管理程序 而每个Block group又细分为 其中: Super Block(超级块):存放文件系统本身的结构信息,主要有block和inode的总量、未使用的block和inode的数量、单个block和inode的大小、最近一次写入数据的时间等等。Super Block对于文件系统而言是至关重要的,所以ext2文件系统会在多个块组中保存超级块的信息 Group Descriptor Table(GDT):块组描述符表,描述块组的属性信息 Block Bitmap(块位图):记录Data blocks中哪些数据块已被使用,哪些数据块未被使用 inode Bitmap(inode位图):记录inode的使用情况 inode Table(inode表):存放inode Data blocks:存放数据块 所以对一个文件的增删查改,实际上就是对文件系统的操作 新建一个文件,在inode位图中找到最近一个未被使用的位置来分配inode并初始化信息,然后根据文件的大小分配数据块并修改inode位图和块位图结构 删除一个文件,将文件所属的inode位图和块位图中的位置修改为0即可(删除即允许被覆盖) 查找一个文件,通过其路径(哪个盘)就可以找到所在分区,然后根据inode编号知道其属于哪个块组的,在inode的位图中确认其是否存在,确认存在就在inode表中取出其inode中的信息并载入内存,通过这些信息找到文件所属的数据块,将这些块拼接得到文件内容 修改一个文件,还是先找到其inode,然后修改对应的属性,如果文件大小发生变动还需要决定是否新增数据块或删除数据块并修改位图 但是问题来了:我是用户,只用文件名,我怎么知道文件的inode编号? 在Linux下一切皆文件,目录也是文件,也有自己的内容和属性,和自己的inode编号 而目录的内容,就是该目录下文件的文件名与inode编号的映射关系! 这也解释了为什么同一目录下不能有同名文件,就像map中不能有相同的key一样 但是,要找一个文件得先知道其目录的inode编号,但是其目录的inode编号又被这个目录的父目录管理着,还得知道父目录的inode编号...一路下去我们就得先从根目录开始找起 这样的方式一定程度上会影响效率,所以系统把我们常访问的目录存到dentry缓存中 简单的介绍了一下文件系统,如有错误欢迎在评论区指出 完. ———————————————— 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 原文链接:https://blog.csdn.net/Eristic0618/article/details/141161151
-
1. 打印命令行提示符 #include<stdlib.h> char* HostName() //获取主机名 { char* ret = getenv("HOSTNAME"); if(ret) return ret; else return (char*)"None"; } char* UserName() //获取用户名 { char* ret = getenv("USER"); if(ret) return ret; else return (char*)"None"; } char* CurrentWorkdir() //获取当前工作目录 { char* ret = getenv("PWD"); if(ret) return ret; else return (char*)"None"; } int main() { //打印命令行提示符 //读取环境变量的内容 / 调用函数(gethostname获取主机名、getcwd获取当前工作目录) printf("[%s@%s %s]#", UserName(), HostName(), CurrentWorkdir()); } 2. 获取用户输入的命令行字符串 可以使用scanf读取字符串吗? 答:不能,scanf用于从标准输入(键盘)读取格式化输入,读取字符串时,scanf会在遇到空白字符(空格、换行符\n、制表符\t等)时停止读取,并将读取的字符串存储到字符数组中。 char* fgets(char* str, int size, FILE* stream); 功能:从指定的文件流stream中读取一行(直到遇到换行符\n、文件结束符EOF、已读取了n-1个字符为止),并将读取的字符串(包括换行符,如果有的话)存储在str指向的数组中,并在数组的末尾添加’\0’来标记字符串的结束。 优点:可以限制读取的字符数,防止缓冲区溢出,并且可以读取包含空格的字符串。 缺点:如果读取的行比指定的长度n还要长,则多余的字符会被留在输入缓冲区中。 文件流stream是程序用于输入和输出的基本抽象,stdin为标准输入流(键盘)、stdout为标准输出流(控制台或终端)、stderr为标准错误输出流。 #include<stdlib.h> #define SIZE 1024 int Interative(char* in) { printf("[%s@%s %s]#", UserName(), HostName(), CurrentWorkdir()); fgets(in, SIZE, stdin); in[strlen(in) - 1] = '\0'; //移除换行字符\n return strlen(in) - 1; //处理空串""情况 } int main() { char CommandLine[SIZE]; //存储用户输入的命令行字符串 while(1) { //打印命令行提示符+获取用户输入的命令行字符串 int n = Interative(CommandLine); if(n == 0) continue; //空串,用户继续输入 } return 0; } char* getcwd(char* buf,size_t size); #include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #define SIZE 1024 char* argv[SIZE]; //相当于main函数的命令行参数表,末尾一定要以NULL结尾 int BuiltinCmd() { int ret = 0; //用于判断是否为内建命令,不是,则为0、是,则为1 if(strcmp("cd", argv[0]) == 0) { ret = 1; char* target = argv[1]; //需要切换的路径 if(!target) target = getenv("HOME"); //cd,表示切换到家目录中 chdir(target); //更改当前工作目录 char tmp[SIZE]; //存储获取到的当前工作目录的绝对路径 char pwd[SIZE]; //存储更改后的环境变量PWD的内容 getcwd(tmp, SIZE); //获取当前工作目录的绝对路径 snprintf(pwd, SIZE, "PWD=%s", tmp); //多变一,拼接 putenv(pwd); //修改环境变量PWD的内容 } return ret; } int main() { char CommandLine[SIZE]; while(1) { //1.打印命令行提示符+获取用户输入的命令行字符串 int n = Interative(CommandLine); if(n == 0) continue; //空串,用户继续输入 //2.分割命令行字符串 Split(CommandLine); //3.处理内建命令 n = BuiltinCmd(); if(n) continue; } return 0; } 4.5. export int BuiltinCmd() { int ret = 0; if(strcmp("export", argv[0]) == 0) { ret = 1; if(argv[1]) { putenv(argv[1]); } } return ret; } 问:为什么第一次export新增环境变量成功,但再输入了其他指令,这个新增的环境变量就不见了? 因为argv为字符指针数组,执行完export后,再输入其他指令,则argv中原有的内容就会被其他指令所覆盖。 char env[SIZE]; //相当于环境变量表,存储新增的环境变量 int BuiltinCmd() { if(strcmp("export", argv[0]) == 0) int ret = 0; { ret = 1; if(argv[1]) { strcpy(env, argv[1]); //将新增的环境变量的内容,拷贝到环境变量表中 putenv(env); } } return ret; } 4.6. echo char env[SIZE]; //相当于环境变量表,存储新增的环境变量 int BuiltinCmd() { if(strcmp("echo", argv[0]) == 0) { ret = 1; if(!argv[1]) //echo:打印一个空行 printf("\n"); else if(argv[1][0] != '$') printf("%s\n", argv[1]); //echo aaaa:打印aaaa else { if(argv[1][1] == '?') { printf("%d\n", exit_code); //echo $?:打印退出码 exit_code = 0; //便于在执行echo $?时,退出码=0 } else printf("%s\n", getenv(argv[1] + 1)); //echo $USER:打印环境变量的内容 } } return ret; } 5. 执行命令 1.Shell脚本编写,bash执行命令时,通常会创建子进程,让子进程执行程序替换。 原因:a. bash是命令行解释器,需要一直执行命令,若让父进程进行替换,执行命令,则父进程就会退出;b. 进程之间具有独立性,子进程进行替换,对父进程无影响。 5.1. 创建子进程进行程序替换 #include<stdlib.h> #include<string.h> #include<sys/types.h> #include<sys/wait.h> #define SIZE 1024 #define SP " " char* argv[SIZE]; int exit_code; //全局变量,存储子进程的退出码,便于echo $?直接输出退出码 void Execute() { pid_t id = fork(); if(id == 0) { execvp(argv[0], argv); //程序替换,执行命令 exit(1); //子进程退出 } int status = 0; pid_t rid = waitpid(id, &status, 0); //父进程等待,进行回收子进程的资源 if(rid > 0) { exit_code = WEXITSTATUS(status); //正常退出,获取子进程的退出码 } } int main() { char CommandLine[SIZE]; while(1) { //1.打印命令行提示符+获取用户输入的命令行字符串 int n = Interative(CommandLine); if(n == 0) continue; //空串,用户继续输入 //2.分割命令行字符串 Split(CommandLine); //4.执行命令(创建子进程,进行替换) Execute(); } return 0; } 6. 重定向 为什么要宏定义多个整数,定义全局变量redir_type? 重定向有三种类型:输出重定向>、追加重定向>>、输出重定向。 我们需要在命令行参数中,查找是否有重定向,如果有重定向,就需要获取重定向的类型,从而在根据重定向的类型执行对应的指令。 所以我们用宏定义多个整数,来表示重定向的类型; 定义一个全局变量redir_type,用来记录获取到的重定向的类型 #define NoneRedir -1 #define StdinRedir 0 #define StdoutRedir 1 #define AppenRedir 2 char* filename = NULL; int redir_type = -1; 1 2 3 4 5 6 7 8 通常来说,重定向由三部分组成:要执行的命令 重定向符号 文件名(如:ls -l > log.txt)。 我们需要获取两部分内容:将要执行的命令进行分割,获取重定向文件。 char* filename = NULL; 1 执行流程:首先判断是否包含重定向(checkRedir);再把我们要执行的命令进行分分割(将重定向字符设置为’\0’,这样strtok只能切割要执行的命令);最后让子进程执行重定向操作。 #define IsSpace(buf, pos) do{while(isspace(buf[pos])) pos ++;}while(0) 1 while(0)目的:可以在使用宏定义的函数处,结尾加上分号(;)可以消除宏和函数之间的这部分差异,让宏看起来更像个函数。 //用宏定义多个整数,来表示重定向的类型 #define NoneRedir -1 #define StdinRedir 0 #define StdoutRedir 1 #define AppenRedir 2 char* filename = NULL; //记录文件名 int redir_type = -1; //记录重定向类型 //去除命令行参数中的空格(连续空格) #define IsSpace(buf, pos) do{while(isspace(buf[pos])) pos++;}while(0) //检查是否包含重定向符号 void CheckRedir(char* in) { filename = NULL; redir_type = -1; int pos = strlen(in) - 1; //从命令行参数字符串后面往前找 while(pos >= 0) { if(in[pos] == '>') { if(in[pos - 1] == '>') //追加重定向 { redir_type = 2; in[pos - 1] = '\0'; //便于将要执行的命令分割开 pos++; //当前pos位置不是空格,isspace函数为假,直接返回 IsSpace(in, pos); //跳过空格 filename = in + pos; //获取文件名 break; //记录完毕,就立即退出 } else //输出重定向 { redir_type = 1; in[pos] = '\0'; pos++; IsSpace(in, pos); filename = in + pos; break; } } else if(in[pos] == '<') //输入重定向 { redir_type = 0; in[pos] = '\0'; pos++; IsSpace(in, pos); filename = in + pos; break; } else { pos--; } } } void Split(char* in) { CheckRedir(in); //在分割之前,先判断是否包含重定向符号 int i = 0; argv[i++] = strtok(in, SP); //首次调用 while(argv[i++] = strtok(NULL, SP)); //后续调用 if(strcmp("ls", argv[0]) == 0) { argv[i-1] = (char*)"--color"; //加上后,ls显示内容,颜色为auto argv[i] = NULL; //argv以NULL结尾,便于子进程在进程程序替换时参数的传递 } } void Execute() { pid_t id = fork(); if(id == 0) { //让子进程执行重定向 int fd = -1; if(redir_type == StdinRedir) { fd = open(filename, O_RDONLY); dup2(fd, 0); //改变文件描述符的执行,从而实现输入、输出重定向 } else if(redir_type == StdoutRedir) { fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666); dup2(fd, 1); } else if(redir_type == AppenRedir) { fd = open(filename, O_WRONLY|O_CREAT|O_APPEND , 0666); dup2(fd, 1); } execvp(argv[0], argv); //程序替换,执行命令 exit(1); //子进程退出 } int status = 0; pid_t rid = waitpid(id, &status, 0); //父进程等待,进行回收子进程的资源 if(rid > 0) { exit_code = WEXITSTATUS(status); //正常退出,获取子进程的退出码 } } 7. 总代码 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<sys/types.h> #include<sys/wait.h> #include<ctype.h> #include<sys/stat.h> #include<fcntl.h> #define SIZE 1024 #define SP " " char* argv[SIZE]; char env[SIZE]; //相当于环境变量表,存储新增的环境变量 int exit_code; //全局变量,存储子进程的退出码,便于echo $?直接输出退出码 //以下都和重定向有关 //用宏定义多个整数,来表示重定向的类型 #define NoneRedir -1 #define StdinRedir 0 #define StdoutRedir 1 #define AppenRedir 2 char* filename = NULL; //记录文件名 int redir_type = -1; //记录重定向类型 //去除命令行参数中的空格(连续空格) #define IsSpace(buf, pos) do{while(isspace(buf[pos])) pos++;}while(0) char* HostName() //获取主机名 { char* ret = getenv("HOSTNAME"); if(ret) return ret; else return (char*)"None"; } char* UserName() //获取用户名 { char* ret = getenv("USER"); if(ret) return ret; else return (char*)"None"; } char* CurrentWorkdir() //获取当前工作目录 { char* ret = getenv("PWD"); if(ret) return ret; else return (char*)"None"; } int Interative(char* in) { printf("[%s@%s %s]#", UserName(), HostName(), CurrentWorkdir()); fgets(in, SIZE, stdin); in[strlen(in) - 1] = '\0'; //移除换行字符\n return strlen(in) - 1; //处理空串""情况 } //检查是否包含重定向符号 void CheckRedir(char* in) { filename = NULL; redir_type = -1; int pos = strlen(in) - 1; //从命令行参数字符串后面往前找 while(pos >= 0) { if(in[pos] == '>') { if(in[pos - 1] == '>') //追加重定向 { redir_type = 2; in[pos - 1] = '\0'; //便于将要执行的命令分割开 pos++; //当前pos位置不是空格,isspace函数为假,直接返回 IsSpace(in, pos); //跳过空格 filename = in + pos; //获取文件名 break; //记录完毕,就立即退出 } else //输出重定向 { redir_type = 1; in[pos] = '\0'; pos++; IsSpace(in, pos); filename = in + pos; break; } } else if(in[pos] == '<') //输入重定向 { redir_type = 0; in[pos] = '\0'; pos++; IsSpace(in, pos); filename = in + pos; break; } else { pos--; } } } void Split(char* in) { CheckRedir(in); //在分割之前,先判断是否包含重定向符号 int i = 0; argv[i++] = strtok(in, SP); //首次调用 while(argv[i++] = strtok(NULL, SP)); //后续调用 if(strcmp("ls", argv[0]) == 0) { argv[i-1] = (char*)"--color"; //加上后,ls显示内容,颜色为auto argv[i] = NULL; //argv以NULL结尾,便于子进程在进程程序替换时参数的传递 } } int BuiltinCmd() { if(strcmp("echo", argv[0]) == 0) { ret = 1; if(!argv[1]) //echo:打印一个空行 printf("\n"); else if(argv[1][0] != '$') printf("%s\n", argv[1]); //echo aaaa:打印aaaa else { if(argv[1][1] == '?') { printf("%d\n", exit_code); //echo $?:打印退出码 exit_code = 0; //便于在执行echo $?时,退出码=0 } else printf("%s\n", getenv(argv[1] + 1)); //echo $USER:打印环境变量的内容 } } else if(strcmp("cd", argv[0]) == 0) { ret = 1; char* target = argv[1]; //需要切换的路径 if(!target) target = getenv("HOME"); //cd,表示切换到家目录中 chdir(target); //更改当前工作目录 char tmp[SIZE]; //存储获取到的当前工作目录的绝对路径 char pwd[SIZE]; //存储更改后的环境变量PWD的内容 getcwd(tmp, SIZE); //获取当前工作目录的绝对路径 snprintf(pwd, SIZE, "PWD=%s", tmp); //多变一,拼接 putenv(pwd); //修改环境变量PWD的内容 } else if(strcmp("export", argv[0]) == 0) int ret = 0; { ret = 1; if(argv[1]) { strcpy(env, argv[1]); //将新增的环境变量的内容,拷贝到环境变量表中 putenv(env); } } return ret; } void Execute() { pid_t id = fork(); if(id == 0) { //让子进程执行重定向 int fd = -1; if(redir_type == StdinRedir) { fd = open(filename, O_RDONLY); dup2(fd, 0); //改变文件描述符的执行,从而实现输入、输出重定向 } else if(redir_type == StdoutRedir) { fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666); dup2(fd, 1); } else if(redir_type == AppenRedir) { fd = open(filename, O_WRONLY|O_CREAT|O_APPEND , 0666); dup2(fd, 1); } execvp(argv[0], argv); //程序替换,执行命令 exit(1); //子进程退出 } int status = 0; pid_t rid = waitpid(id, &status, 0); //父进程等待,进行回收子进程的资源 if(rid > 0) { exit_code = WEXITSTATUS(status); //正常退出,获取子进程的退出码 } } int main() { char CommandLine[SIZE]; while(1) { //1.打印命令行提示符+获取用户输入的命令行字符串 int n = Interative(CommandLine); if(n == 0) continue; //空串,用户继续输入 //2.分割命令行字符串 Split(CommandLine); //3.处理内建命令 n = BuiltinCmd(); if(n) continue; //4.执行命令(创建子进程,进行替换 Execute(); } return 0; } ———————————————— 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 原文链接:https://blog.csdn.net/m0_74808907/article/details/142133792
-
Linux查看硬盘信息的几种命令包括df、du、lsblk、fdisk、smartctl。 一、 df命令 df -h 是最常见的磁盘查看命令。它可以显示文件系统的总大小、已用空间、可用空间和挂载点等信息。 [root@FZCTP-DB ~]# df -h Filesystem Size Used Avail Use% Mounted on /dev/mapper/centos-root 110G 46G 65G 42% / /dev/mapper/centos-data 1.9T 1.5T 389G 80% /data /dev/vda2 1014M 196M 819M 20% /boot /dev/vdb1 1.0T 14G 1011G 2% /backup tmpfs 41G 12G 30G 29% /dev/shm tmpfs 32G 2.2G 30G 7% /run tmpfs 32G 0 32G 0% /sys/fs/cgroup tmpfs 6.3G 40K 6.3G 1% /run/user/0 tmpfs 6.3G 0 6.3G 0% /run/user/1001 /dev/sr0 4.3G 4.3G 0 100% /mnt/cdrom devtmpfs 32G 0 32G 0% /dev “Size”表示文件系统总大小,“Used”表示已使用大小,“Avail”表示可用空间linux启动盘制作工具,“Use%”表示已使用百分比 二、du 命令 du命令是用于查看目录或文件占用磁盘空间的命令。 常用命令和选项,统计当前目录下的文件和目录占用空间 [root@FZCTP-DB ~]# du -sh * 4.0K anaconda-ks.cfg 4.0K Desktop 4.0K Documents 20K Downloads 64K install.log 12K install.log.syslog 11G logs 4.0K Music 4.0K Pictures 4.0K Public 436K soft -s, --summarize 仅显示总计,只列出最后加总的值。 -h, --human-readable 以K,M,G为单位,提高信息的可读性。 常看指定目录下所有文件的大小(会遍历所有文件) [root@FZCTP-DB tomcat]# du -h apache-tomcat-9.0.36/ 6.5M apache-tomcat-9.0.36/webapps/java/applets 16K apache-tomcat-9.0.36/webapps/java/WEB-INF/classes/com/bstek/dorado/uploader/resolver 20K apache-tomcat-9.0.36/webapps/java/WEB-INF/classes/com/bstek/dorado/uploader 16K apache-tomcat-9.0.36/webapps/java/WEB-INF/classes/com/bstek/dorado/view/output 20K apache-tomcat-9.0.36/webapps/java/WEB-INF/classes/com/bstek/dorado/view/resolver 48K apache-tomcat-9.0.36/webapps/java/WEB-INF/classes/com/bstek/dorado/view 12K apache-tomcat-9.0.36/webapps/java/WEB-INF/classes/com/bstek/dorado/web/resolver 16K apache-tomcat-9.0.36/webapps/java/WEB-INF/classes/com/bstek/dorado/web 88K apache-tomcat-9.0.36/webapps/java/WEB-INF/classes/com/bstek/dorado 36K apache-tomcat-9.0.36/webapps/java/WEB-INF/classes/com/bstek/bdf2/export/excel 12K apache-tomcat-9.0.36/webapps/java/WEB-INF/classes/com/bstek/bdf2/export/csv 将文件从大到小排序 du -sh * |sort -rh 三、lsblk命令 lsblk该命令可以列出系统中所有块设备(如硬盘、SSD 等)的信息,包括设备名称、容量、挂载点等。通过这个命令可以方便地了解系统硬件配置和磁盘分区情况。 [root@FZCTP-DB ~]# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 558.9G 0 disk |-sda1 8:1 0 500M 0 part /boot/efi |-sda2 8:2 0 500M 0 part /boot `-sda3 8:3 0 557.9G 0 part |-vg_fzctpdb-LogVol00_swap (dm-0) 253:0 0 64G 0 lvm [SWAP] |-vg_fzctpdb-LogVol04_root (dm-1) 253:1 0 453.9G 0 lvm / |-vg_fzctpdb-LogVol03_var (dm-2) 253:2 0 20G 0 lvm /var |-vg_fzctpdb-LogVol02_usr (dm-3) 253:3 0 10G 0 lvm /usr `-vg_fzctpdb-LogVol01_tmp (dm-4) 253:4 0 10G 0 lvm /tmp 四、fdisk命令 fdisk 命令可以显示系统中所有硬盘的分区情况,包括分区类型、容量、起始位置等信息。通过这个命令可以查看系统磁盘的物理结构和分布情况。 [root@FZ-DB ~]# fdisk -l Disk /dev/sda: 600.1 GB, 600093712384 bytes 255 heads, 63 sectors/track, 72957 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 262144 bytes / 262144 bytes Disk identifier: 0x00000000 Device Boot Start End Blocks Id System /dev/sda1 1 72958 586029015+ ee GPT Partition 1 does not start on physical sector boundary. Disk /dev/mapper/vg_fzctpdb-LogVol00_swap: 68.7 GB, 68719476736 bytes 255 heads, 63 sectors/track, 8354 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 262144 bytes / 262144 bytes Disk identifier: 0x00000000 Disk /dev/mapper/vg_fzctpdb-LogVol04_root: 487.4 GB, 487369736192 bytes 255 heads, 63 sectors/track, 59252 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 262144 bytes / 262144 bytes Disk identifier: 0x00000000 Disk /dev/mapper/vg_fzctpdb-LogVol03_var: 21.5 GB, 21474836480 bytes 255 heads, 63 sectors/track, 2610 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 262144 bytes / 262144 bytes Disk identifier: 0x00000000 Disk /dev/mapper/vg_fzctpdb-LogVol02_usr: 10.7 GB, 10737418240 bytes 255 heads, 63 sectors/track, 1305 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 262144 bytes / 262144 bytes Disk identifier: 0x00000000 Disk /dev/mapper/vg_fzctpdb-LogVol01_tmp: 10.7 GB, 10737418240 bytes 255 heads, 63 sectors/track, 1305 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 262144 bytes / 262144 bytes Disk identifier: 0x00000000 五、smartctl命令 smartctl命令是用于检测硬盘健康状态并显示相关信息的命令。它可以显示硬盘的温度、寿命预测、错误记录等信息。 [root@FZ-DB ~]# smartctl -a /dev/sda smartctl 5.43 2016-09-28 r4347 [x86_64-linux-2.6.32-696.el6.x86_64] (local build) Copyright (C) 2002-12 by Bruce Allen, http://smartmontools.sourceforge.net Vendor: HP Product: LOGICAL VOLUME Revision: 5.52 User Capacity: 600,093,712,384 bytes [600 GB] Logical block size: 512 bytes Logical Unit id: 0x600508b1001c13ef256161d9825110ea Serial number: PDNLH0BRH981LP Device type: disk Local Time is: Wed Jun 19 10:24:12 2024 CST Device supports SMART and is Enabled Temperature Warning Disabled or Not Supported SMART Health Status: OK Error Counter logging not supported Device does not support Self Test logging https://www.linuxcool.com/lypkjzkmlff https://zhuanlan.zhihu.com/p/688628108 ———————————————— 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 原文链接:https://blog.csdn.net/u011475248/article/details/139795422
-
Linux telnet命令介绍 telnet(Teletype Network)是一种网络协议,用于在远程主机和本地计算机之间建立文本式连接。它最初于1969年开发,是Internet的早期协议之一。telnet命令使用TCP/IP网络通过端口23建立连接,提供了一种通过命令行界面管理远程系统的方式。 Linux telnet命令适用的Linux版本 telnet命令在大多数Linux发行版中都可以使用,但可能需要手动安装。以下是在不同Linux发行版中安装telnet的方法: Debian/Ubuntu:使用apt包管理器安装。 [linux@bashcommandnotfound.cn ~]$ sudo apt update [linux@bashcommandnotfound.cn ~]$ sudo apt install telnetd -y 1 2 CentOS/RHEL/Fedora:使用yum或dnf包管理器安装。注意,CentOS 7和CentOS 8的安装工具可能不同。 [linux@bashcommandnotfound.cn ~]$ sudo yum update [linux@bashcommandnotfound.cn ~]$ sudo yum install telnet telnet-server -y 1 2 Linux telnet命令的基本语法 telnet命令的基本语法格式如下: telnet [-468EKLadr] [-Xa authtype] [-b hostalias] [-e escapechar] [-l user] [-n tracefile] [ host [port] ] 1 Linux telnet命令的常用选项或参数说明 选项 说明 -4 强制使用IPv4地址 -6 强制使用IPv6地址 -8 允许8位输入数据 -E 禁止回显 -K 不自动登录到远程主机 -L 允许8位输出数据 -a 尝试自动登录 -b hostalias 使用主机别名代替真实主机名 -d 启用调试模式 -e escapechar 设置转义字符 -l user 自动登录为用户 -n tracefile 记录输入和输出信息到文件 -r 使用远程数据连接 host 指定要连接的远程主机 port 指定要连接的远程主机的端口号 Linux telnet命令实例详解 实例1:连接到远程主机 [linux@bashcommandnotfound.cn ~]$ telnet example.com 1 这个命令将连接到名为example.com的远程主机。 实例2:指定端口连接到远程主机 [linux@bashcommandnotfound.cn ~]$ telnet example.com 23 1 这个命令将连接到名为example.com的远程主机的23端口。 实例3:使用IPv4地址连接到远程主机 [linux@bashcommandnotfound.cn ~]$ telnet -4 example.com 1 这个命令将强制使用IPv4地址连接到名为example.com的远程主机。 实例4:使用IPv6地址连接到远程主机 [linux@bashcommandnotfound.cn ~]$ telnet -6 example.com 1 这个命令将强制使用IPv6地址连接到名为example.com的远程主机。 实例5:禁止回显 [linux@bashcommandnotfound.cn ~]$ telnet -E example.com 1 这个命令将禁止回显,连接到名为example.com的远程主机。 实例6:不自动登录到远程主机 [linux@bashcommandnotfound.cn ~]$ telnet -K example.com 1 这个命令将不自动登录到名为example.com的远程主机。 实例7:尝试自动登录 [linux@bashcommandnotfound.cn ~]$ telnet -a example.com 1 这个命令将尝试自动登录到名为example.com的远程主机。 实例8:使用主机别名代替真实主机名 [linux@bashcommandnotfound.cn ~]$ telnet -b example example.com 1 这个命令将使用主机别名example代替真实主机名example.com。 实例9:启用调试模式 [linux@bashcommandnotfound.cn ~]$ telnet -d example.com 1 这个命令将启用调试模式,连接到名为example.com的远程主机。 实例10:设置转义字符 [linux@bashcommandnotfound.cn ~]$ telnet -e ! example.com 1 这个命令将设置转义字符为!,连接到名为example.com的远程主机。 实例11:自动登录为用户 [linux@bashcommandnotfound.cn ~]$ telnet -l user example.com 1 这个命令将自动登录为用户user,连接到名为example.com的远程主机。 实例12:记录输入和输出信息到文件 [linux@bashcommandnotfound.cn ~]$ telnet -n tracefile example.com 1 这个命令将记录输入和输出信息到文件tracefile,连接到名为example.com的远程主机。 实例13:使用远程数据连接 [linux@bashcommandnotfound.cn ~]$ telnet -r example.com 1 这个命令将使用远程数据连接,连接到名为example.com的远程主机。 实例14:指定要连接的远程主机的端口号 [linux@bashcommandnotfound.cn ~]$ telnet example.com 8080 1 这个命令将连接到名为example.com的远程主机的8080端口。 实例15:连接到远程主机并执行命令 [linux@bashcommandnotfound.cn ~]$ echo "ls /" | telnet example.com 1 这个命令将连接到名为example.com的远程主机,并在远程主机上执行ls /命令。 Linux telnet命令的注意事项 telnet命令发送的数据不加密,因此可能容易成为黑客的目标。 如果在尝试使用telnet命令时收到bash: telnet: command not found的错误消息,可能需要安装telnet。 ———————————————— 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 原文链接:https://blog.csdn.net/u012964600/article/details/136963732
-
一、硬件体系 首先我们要知道,我们最常见的计算机(笔记本)以及我们不常见的计算机(服务器)其实本质上都是一堆硬件的结合:cpu、网卡、显卡、内存、磁盘、显示器、键盘…… 但他们并不是毫无章法地放在一起,硬件和硬件之间需要有效地组织成一个系统才能更好地发挥功能,我们把这个组织结构叫做冯诺依曼体系结构! 1.1 冯诺依曼体系结构介绍 a、输入设备:鼠标、键盘、摄像头、话筒、磁盘(文件读取)、网卡(网络接受)…… b、输出设备:显示器、播放器硬件、磁盘(写入文件)、网卡(网络发送)…… 计算机只能识别二进制语言,所以人和计算机打交道,必须要借助输入输出设备,并且我们会发现有的设备是纯的输入或输出,而有的设备既有输入也有输出 c、存储区:内存 运行程序、读取文件、写入文件……等大部分操作都是在内存中进行的! d、运算器:对我们的数据进行计算任务(算数运算、逻辑运算) e、控制器:对我们的计算机硬件流程进行一定的控制 运算器和控制器统称为中央处理器(CPU) 冯诺依曼体系结构由以上五个部分组成,但我们要知道每一个硬件都是独立的个体,所以想要建立联系协同起来,必须借助“线”进行连接!!我们把它叫做总线,总线又分为系统总线和IO总线 系统总线:存储区和运算器、控制器之间的线 IO总线:存储区和输入设备、输出设备之间的线 1.2 冯诺依曼为什么要这么设计? 我们会发现一个问题就是,输入设备和输出设备并不直接跟中央处理器打交道,他们都只跟存储器打交道,所以存储器(内存)在这个过程中发挥了串联整个线路的作用!我们接下来就要分析为什么要这么去设计!! 1.2.1 提高工作效率 以下是计算机存储的金字塔层次结构: CPU的速度是纳秒级别的,而硬盘是毫秒级别的,所以他们的速度差距太大了!!因此需要内存(微秒级别)在中间做一个和事佬。 1.2.2 串型变成并型 其实CPU和硬盘,很容易让你想到木桶效应,就是木桶能接多少水取决于他的短板,而同理计算机运行有多快似乎也应该取决于硬盘,但如果真的是这样的话,那我们加入内存的意义在哪呢?不也是会相互拖慢速度吗?? 其实你会这么想的原因是,你把这套体系理解为串型了,就是单纯认为中央处理器一定要等到数据全都加载到存储器的才会去工作,其实在我们将数据从输入设备加载到存储器时,中央处理器可能并没有闲着,而是在处理别的工作!!他们是一个并型逻辑!! 举个例子:比如说二进制可执行程序其实也是文件,文件是在磁盘上存储的,我们要运行这个程序就必然要将其先读取到内存中,而当外部设备在将数据加载到内存中时,其实cpu可能正在进行其他的运算,当你把数据预先都加载到内存中的时候,cpu恰好开始执行你的代码,所以我们会发现cpu从存储器中拿数据和外部设备导入到存储器这两个过程是可以同时进行的!!所以这是并型而不是串型!!大大提高了效率!!这也是内存存在的真正价值!! 1.2.3 有利于计算机的传播 通过计算机存储的金字塔结构,我们会发现越往下成本越低、容量越大、速度越慢,这是一个有舍有得的过程,那如果我一点也不差钱,那我是不是可以全部都用寄存器?不要内存也不要磁盘?也不需要遵守冯诺依曼体系? 答案其实是应该可以做到的!!如果你特别有钱,或许真的可以让别人给你定制一个只靠寄存器的计算机,但是这个计算机必然是造价特别贵的。老百姓是用不起的!! 其实我们是否会去使用这个计算机,一方面是考虑是否易操作、性能好,另一方面也要考虑成本!!所以冯诺依曼体系中为什么要有内存,也是因为我们不仅需要中央处理器,但是为了控制成本也不得不有硬盘,所以才需要有一个速度适中、容量也适中的存储器,这样可以在不降低太多性能的前提下降低成本,能够让老百姓去使用!! 通过此时的冯诺依曼体系结构,包括开源的Linux和git,我们会发现其实一样东西是否能够被快速传播,成本是十分重要的,价格太高是不利于传播的,其实现在市面上或许也会存在很多能够造福于百姓的创造,但是可能由于成本太高无法推广给普通老百姓,所以必然也是会沉没在历史的巨轮中。比如我们看过的一个电影叫《我不是药神》,其中抗癌正版药非常贵才会让老百姓不惜犯罪也要去吃盗版药。也是这个道理!! 1.3 实际应用 冯诺依曼体系中最为关键的就是内存!!我们可以很好地解释以下知识: 1、为什么一个程序要运行必须要先加载到内存中?? ——>这是由冯诺依曼体系决定的, 程序其实就是一个二进制文件,文件就是存储在磁盘(外部设备)中的,要去中央处理器那里才能运行,所以必须要先加载到内存中!! 2、我们之前写的进度条,如果不换行的话,数据会被存储到缓存中,那么缓存在哪?? ——>根据冯诺依曼体系结构,我们可以知道缓存其实就在内存中!! 3、如果我想把实验报告通过qq发送给我的好友,如何用冯诺依曼体系来分析整个数据流?? 二、OS体系 每个硬件都有他对应的功能并且能够安装冯诺依曼体系去很好地工作,但是这是远远不够的,因为什么时候需要去执行什么功能是需要有人去调控的。 举个例子:假设你是一个国家的国王,这个国家里有擅长搞经济的,有擅长打仗的,有擅长谈判的,有擅长艺术的……当你想要听声乐,你会去叫搞艺术的人过来,当国家和平时期,你会重点培养搞经济的人,当外敌来犯,如果你想和解,你会叫擅长谈判的人来,你想打仗,你就会叫擅长打仗的人来…………所以这整个逻辑都是需要有人去调控的,在计算机中也是如此。 所以可能你的电脑中同时运行了qq、qq音乐、cctalk……那我什么时候该运行先哪个,运行qq的时候,凭什么不先运行qq音乐呢??所以我们需要有一个大脑一样的角色去管理他们——OS OS是一款可以管理软硬件资源的软件,就像人可以管理人也可以管理机器一样!! 2.1 OS存在的意义(为什么) 2.1.1 给用户提供良好(稳定、高效、安全)的运行环境 无论我们上层是什么样的,最终的行为都是在硬件上体现的,软件想要操控硬件,就必然需要一些能够与硬件建立联系的驱动程序。比如说鼠标,当你刚把数据线接上的时候,从物理上你已经连接到你的电脑上了,但是你可能还需要等待几秒才真的可以去使用,因为驱动程序一开始还没有马上被加载出来——>驱动程序是我们和硬件打交道的软件(大部分是系统自带的) OS是一个帮助我们管理软硬件资源的角色,但这仅仅只是他的手段罢了,他的目的是为了给用户提供一个良好(稳定、高效、安全)的运行环境,但我们要知道其实普通用户是不善于和OS打交道的,所以普通用户使用的都是基于程序员开发出来的软件,所以首先是我们专业的程序员需要去跟OS打交道,然后再搞出满足普通用户需求的各种软件!! 所以后面我们要探究的就是,程序员究竟如何和OS打交道呢?? 2.1.2 OS其实不信任用户 OS里面有各种各样的数据,但是OS并不信任用户!! 首先我们要理解的是,不相信你和让你使用其实是不矛盾的,举个例子:银行允许任何用户进来,但是他其实并不相信所有的用户,因为用户当中可能会有坏人,所以银行为了保护自己需要封闭起来,但是不能完全封闭,因为这样就无法给老百姓提供服务了,所以他开放了一些小小的窗口,如果你普通用户想要取钱、借贷……只能通过这个小窗口来申请!! 同理,OS也觉得自己的数据太重要了,他担心坏人恶意攻击他,也担心小白随意篡改他,无论有意无意都有可能对他造成伤害,比如说一个磁盘可能有500G,但是有人给他改成了300G;你的网络本该是良好的,但是却被改成断开……所以OS也得像银行一样,把自己封闭起来,但是留一些小小的窗口出来(在计算机中称为接口)——>所以OS的设计者用C语言写了一些内部的函数方法开放给外部,我们把它称之为系统调用! 因为这些接口都是由设计者提供的,所以他的内部自然会存在一些方法能够检测你的行为是否非法,只有合法的行为才能访问他的数据。 ——>因此未来我们想跟OS打交道,只能通过系统调用来完成!! ——>但是系统调用本身使用难度也很大,所以就需要程序员基于系统调用去设计一些上层的软件或者接口去供普通用户使用。 2.1.3 OS和计算机语言的区别 其实语言的本质就是:头文件+库文件+编译器=可执行程序 1、所以语言实际上是基于系统调用接口之上存在的!!但是语言之间也是有区别的,比如说java、python、虚拟机等底层是用C或C++写的,所以哪怕是我们常说C/C++是偏底层的语言,但他实际上也只是在系统调用之上而已。所以我们可以有一个很好的边界认识。 2、任何语言访问硬件都需要经过操作系统,所以我们会发现,语言可能会变,但是操作系统是不会变的,因为下层如果改变的,整个上层的逻辑都会崩盘,再牛逼的软件也必须遵守这套体系。我们常说的计算机发展很快其实都指的是上层,下层的变化是不大的。 2.2 OS的管理方法(怎么做) 2.2.1 如何管理 为了能够更好地去理解管理,我们举个生活中的例子: 问题1:在学校里,校长是我们公认的管理者,我们学生是公认的被管理者,可是我们大多数人却没有见过校长,但是校长依旧可以把我们所有人都管理得很好,这是为啥??? 所以首先我们可以得到一个观点1:管理者和被管理者之间是不需要见面的!! 问题2:那么管理者在不见被管理者的情况,是如何做好管理的呢?? 比如说学校需要选出几个人去参加数学竞赛,我只需要知道哪几个学生的数学水平比较高就可以了,如果学校想给前10名奖学金,只需要给成绩排个序取前10名就可以了。比如我作为一个老板,我知道一个员工一年拿下了特别多的项目为公司创造了特别多的利润,业绩排名第一,我在不见到他的情况下通过他的表现就可以做出给他升职加薪的决策,所以我们会发现,对于管理者来说,只要知道管理信息,就可以在未来进行管理决策。所以管理的本质是通过对数据的管理,达到对人的管理!即使是在小公司我们和管理者能够见面,管理者关注的也无非就是管理信息。 问题3:那管理者究竟是如何拿到数据的呢?? 如果是在学校,大家可能会想到辅导员(充当执行者),在管理者和被管理者其实还夹杂着执行者,因为一件事情除了决策还需要有人去执行!比如说校长想知道哪些人能够有资格去参加程序设计比赛,然后他就可以喊辅导员过来,辅导员(执行者)和学生(被管理者)走的比较近相对比较了解,或许就可以通过辅导员拿到对应的信息。这确实是有一定道理,但是如果规模比较大的话,比如大学里面,一个辅导员手下就有几百号人,一个校长手下就有几千甚至上万人……他们同时面对这么多数据,肯定忙不过来啊!!所以通过人去拿数据,不是不行,但是能力比较有限。所以我们换个角度思考,我们不就是想要知道一些基本信息吗,而学生虽然各有特点,但都是相同的属性。比如说张三和李四的学院、专业、电话、年龄、籍贯、身高、体重、各科成绩、兴趣爱好…………直接把这些我们想要知道的信息管理起来,不就可以解决这个问题了吗。你第一时间可能会想到用个excel表格,这是大部分人能想到的,但是比方说人数特别多,然后你想在对应的信息里找到比方说前5个数学最好的学生,那你可能得花费很多时间用眼睛去扫描数据,也挺累的其实,其实我们作为程序员,还有更好的办法,就是用结构体管理起来。 我们每入学一个学生,就可以新建一个学生类型,而每毕业一个学生,就可以删除一个学生类型,但是学生不只有一个啊!!所以我们需要把它管理起来,而对数据进行管理,当然就是数据结构啦!!那我们就可以在每一个学生结构体里面加一个next指针,这样就可以把所有学生的信息都串起来变成一个链表了!!所以我们就把对学生的管理转变成了对链表的管理!!! 转变为链表的管理和相比用excel有什么好处呢?? ——>对链表的管理本质上就是对链表的增删改查,所以我们可以根据链表的特点去写很多我们需要的一些接口。比方说我想找到数学成绩最好的10个学生,那么直接写一个相关的接口,而后每次我们只要调用这个接口就可以完成这件事,就不需要在excel里面一个一个去看了!! 综上我们进行一下总结: 1、管理者和被管理者是不需要见面的 2、管理者只需要得到管理信息,就可以做出管理决策,所以管理的本质是通过对数据的管理从而实现对人的管理 3、管理者一方面可以通过执行者去拿到数据,另一方面可以通过将被管理者的一些信息用结构体描述出来,然后再用数据结构组织在一起,然后再通过该数据结构的特点实现相关需求的算法来拿到数据。 在计算机体系结构里,我们的OS就相当于管理者,我们的软硬件资源就相当于被管理者,而我们的驱动程序就相当于是执行者。 2.2.2 理解先描述再组织 在理解如何管理之后,我们发现了管理者通过描述出被管理者的结构体,然后再通过数据结构组织起来,然后再实现一些相关的算法去实现管理。所以就引申出了一个概念——先描述再组织 思考一下我们以前写的通讯录应该是怎么写呢?? 首先我们的通讯录里面要有人,肯定要先把人给描述出来,比如说有名字、电话、年龄……然后我们再用通讯录把这些人的对象管理起来,然后基于这个通讯录去实现一些接口:比如删除联系人、增加联系人、查找联系人…… 所以我们可以得到一个结论就是:其实未来我们无论开发任何软件,其实都是按照先描述再组织的形式去思考!! 再思考一下我们学习C++的正确顺序,首先我们先是学的类与对象,这是描述,而后我们学了内存、STL,其实就是在学习怎么进行组织………所以我们学习语言的顺序也是按照先描述再组织的思路去学的!! 另外再OS中,我们还可以知道:在OS中管理任何的对象最终都可以转化为对某种数据结构的增删查改!! 2.2.3 理解库文件vs系统调用 先举个例子,假如有A和B两个校长,A校长有一个学生数学特别厉害,但是B校长没有,于是B校长就想跟A校长商量借这个同学来打比赛,但是B校长肯定不能直接去找这个学生,因为这个学生是A校长的人,他得负责,所以他必须要通过A校长的同意才行。 同理我们通过printf把“hello”打在屏幕上,其实并不是我们直接通过调用这个库函数就和硬件打交道了,而是必须要自上而下贯穿下去,也就是要通过系统调用接口然后让OS知道!!! 所以我们知道了库函数必须通过系统调用接口才能找到OS,所以库函数和系统调用是上下层的关系,库函数是基于系统调用之上的二级开发!! ———————————————— 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 原文链接:https://blog.csdn.net/weixin_51142926/article/details/140936732
-
Linux 中定时任务 crontab 的使用详解在 Linux 系统中,crontab 是一个非常实用的工具,用于设置定时任务。它可以让我们在特定的时间自动执行命令、脚本或程序,极大地提高了工作效率和系统的自动化程度。本文将详细介绍 crontab 的使用方法,并包含代码示例。一、crontab 简介crontab 是一个用于在特定时间执行任务的工具,它基于 cron 守护进程运行。cron 守护进程会在系统启动时自动启动,并定期检查 crontab 文件中的任务列表,以确定是否需要执行某个任务。二、crontab 的基本语法crontab 的语法格式如下:* * * * * command_to_execute其中,五个星号分别代表分钟、小时、日、月、周几。command_to_execute 是要执行的命令或脚本。例如,以下 crontab 条目表示每分钟执行一次echo "Hello, world!"命令:* * * * * echo "Hello, world!"三、crontab 的时间表示法分钟(0-59)可以使用具体的分钟数,如15表示在 15 分钟时执行任务。也可以使用通配符*表示每分钟都执行任务。还可以使用范围表示法,如10-20表示在 10 到 20 分钟之间的每分钟都执行任务。可以使用步长表示法,如*/5表示每隔 5 分钟执行一次任务。小时(0-23)与分钟的表示法类似,可以使用具体的小时数、通配符、范围表示法和步长表示法。日(1-31)可以使用具体的日期,如15表示在每月的 15 日执行任务。也可以使用通配符*表示每天都执行任务。可以使用范围表示法,如10-20表示在每月的 10 到 20 日之间的每天都执行任务。可以使用步长表示法,如*/5表示每隔 5 天执行一次任务。月(1-12)可以使用具体的月份,如5表示在 5 月执行任务。也可以使用通配符*表示每月都执行任务。可以使用范围表示法,如5-8表示在 5 月到 8 月之间的每月都执行任务。可以使用步长表示法,如*/3表示每隔 3 个月执行一次任务。周几(0-6,0 表示周日)可以使用具体的周几,如3表示在周三执行任务。也可以使用通配符*表示每周都执行任务。可以使用范围表示法,如2-4表示在周二到周四之间的每周都执行任务。可以使用步长表示法,如*/2表示每隔 2 周执行一次任务。四、crontab 的使用步骤编辑 crontab 文件使用crontab -e命令编辑当前用户的 crontab 文件。如果是第一次编辑,系统可能会提示你选择一个文本编辑器。在打开的文件中,按照 crontab 的语法格式添加任务条目。保存并退出编辑完成后,保存文件并退出编辑器。cron 守护进程会自动读取新的 crontab 文件,并按照其中的任务条目执行任务。查看 crontab 任务列表使用crontab -l命令可以查看当前用户的 crontab 任务列表。删除 crontab 任务使用crontab -r命令可以删除当前用户的所有 crontab 任务。五、代码示例以下是一些 crontab 任务的代码示例:每天凌晨 2 点执行备份脚本0 2 * * * /path/to/backup_script.sh每周一到周五的上午 9 点执行清理日志文件的脚本0 9 * * 1-5 /path/to/clean_logs_script.sh每月 1 日和 15 日的下午 3 点执行数据库备份脚本0 15 1,15 * * /path/to/database_backup_script.sh每隔 10 分钟执行一次检查服务器状态的脚本*/10 * * * * /path/to/check_server_status_script.sh六、注意事项任务执行的环境变量crontab 任务执行时的环境变量可能与用户登录时的环境变量不同。如果任务需要特定的环境变量,可以在任务条目中设置环境变量,或者在脚本中显式地设置环境变量。任务执行的输出和错误处理默认情况下,crontab 任务的输出会通过邮件发送给用户。如果任务的输出较多或者不需要邮件通知,可以将输出重定向到文件或者/dev/null。如果任务执行出现错误,可以通过查看系统日志或者邮件来确定错误原因。任务的安全性确保任务执行的命令或脚本具有足够的权限,并且不会对系统造成安全风险。避免在 crontab 任务中使用敏感信息,如密码等。如果任务需要使用敏感信息,可以将敏感信息存储在安全的地方,并在任务执行时读取。总之,crontab 是一个非常强大的工具,可以帮助我们实现系统的自动化管理。通过合理地设置 crontab 任务,我们可以提高工作效率,减少人工干预,并且确保系统的稳定运行。希望本文对大家在使用 crontab 时有所帮助。
上滑加载中
推荐直播
-
华为云码道Agent集成与鸿蒙实战2026/08/11 周二 19:00-21:00
王一男-华为云码道产品规划专家;李炎-华为云码道产品专家;彭江敏-华为云鸿蒙端云一体化开发专家
本次直播带你解读华为云码道7月份产品新特性、新功能。更有专家演示码道Agent Space × 钉钉机器集成实战,从0到1打通消息通道;码道鸿蒙端云一体化实战,快速搭建员工签到系统。
回顾中 -
华为云开发者AI素养直播课·第五期2026/09/04 周五 16:00-18:00
林华鼎-华为云AI开发者运营负责人;蒋春阳-华为云AI开发者案例开发专家
本期直播内容: AI工具体验营 · 第5-8课连讲。Agent-Team 多智能体协作完成毕业设计实践
回顾中 -
华为云开发者AI素养ClassRoom·第六期2026/09/08 周二 19:00-20:00
樊渊-2026华为软件挑战赛冠军
高手来了:看软挑高手解析二维排样问题—从工业难题到算法突破
回顾中
热门标签