做教育网站的公司,wordpress怎么登陆ftp,爱站网ip反域名查询,网站建设有什么好处操作系统 传统的计算机系统资源分为硬件资源和软件资源。硬件资源包括中央处理器#xff0c;存储器#xff0c;输入设备#xff0c;输出设备等物理设备#xff1b;软件资源是以文件形式保存在存储器上的成熟和数据等信息。 操作系统就是计算机系统资源的管理者。 如果你的计… 操作系统 传统的计算机系统资源分为硬件资源和软件资源。硬件资源包括中央处理器存储器输入设备输出设备等物理设备软件资源是以文件形式保存在存储器上的成熟和数据等信息。 操作系统就是计算机系统资源的管理者。 如果你的计算机没有安装操作系统那么你将面对的是01代码和一些难懂的机器指令通过按钮或者按键来操作计算机这样笨拙费时。安装操作系统之后你面对的就不再是笨拙的裸机而是操作便利服务周到的操作系统从而明显的改善了用户界面。 操作系统为了保证自己的安全也为了保证给用户能够提供服务就以接口的方式给用户提供调用的入口来获取操作系统内部的数据。 这个接口是操作系统提供的用C语言实现的自己内部的函数调用---系统调用 所有访问操作系统的行为都只能通过系统调用完成因为操作系统不会让你随意的去对自己进行更改。 所以操作系统就是一个管理者利用操作系统能够有效的组织和管理系统中的各种软硬件资源合理的组织计算机系统工作的流程控制程序的执行并且向用户提供一个良好的工作环境和友好的接口。程序猿通过暴露出的接口开发出来各种软件供普通用户使用。 那么操作系统是如何管理的呢 在学校中我们就是最典型的被管理者校长是管理者。管理者与被管理者是不需要见面的查考勤情况的活肯定不是校长监督的吧。那么校长连A同学都不知道是谁怎么管理好这么多同学呢 其实只要校长拿到了学生的数据就能进行管理见不见面不是必须的就算见面了也是为了获取某同学的数据。管理的本质是通过对数据的管理达到对人的管理。 但是不见面的情况下校长是怎么知道A同学挂没挂科呢这些数据都可以通过辅导员来拿到数据。 在这里校长相当于操作系统辅导员相当于驱动程序学生相当于软硬件资源。所以操作系统要管理好软硬件资源是通过获取硬件的各种状态数据来进行管理这个数据从驱动程序中获得。一个硬件不能用了驱动程序把信息传递给操作系统操作系统告知用户。 学校中的学生很多他弄了一个excel表格让辅导员按照这个表格获取学生的信息辅导员获取完信息后在把表格给校长现在校长要找谁个子最高等信息只需要遍历一遍表格即可。这个过程就是一个描述的过程。 但校长曾经是一个程序猿他弄了一个结构体来实现这个表格。 struct student
{
char 学院[];
char 专业[];
......struct student *next;
}struct student stu1 {}; 每一个结构体对象里面存着学生的信息通过next来对学生进行链接。 所以校长只要把这个学生链表管理好就行了。这样就将对学生的管理工作变成了对链表的增删查改。想找挂科超过3科的直接遍历链表即可。填写学生信息的过程是描述过程把学生通过节点链接起来的过程是组织的过程。 操作系统中管理任何对象最终就变成了对某种的数据结构的管理。操作系统管理的过程跟上面的例子一样先描述在组织。 之前写通讯录之类管理系统先把要存的信息写在结构体中然后对这个结构体进行封装这不就是先描述在组织吗 struct person
{
char name;
int age;
char telphone1;
char telphone2;
...
}struct contact
{
struct person[100];
int num;
...
} 系统调用和库函数概念 操作系统不相信任何人只会提供系统调用接口如果你想简介的访问硬件或者打开文件之类的操作是不能直接访问底层硬件而是层层访问以贯穿的形式。比如说printf函数他是C标准函数他的底层绝对要封装系统调用接口所以C/C封装的库函数和系统调用接口的关系是上下层被调用的关系而不是直接绕过系统调用接口直接访问的。 那么谁在上谁在下呢 库函数在上系统调用接口在下 在开发的角度操作系统对外表现为一个整体但是会暴露一部分接口供程序猿开发使用这部分由操作系统提供的接口叫做系统调用
系统调用在使用上 功能比较基础对用户的要求也相对较高所以有些开发者可以对部分系统调用进行适度封装从而形成了库有了库就很利于上层用户或者开发者进行二次开发 进程 一个已经加载到内存中的程序叫做进程。 这些已经打开的软件都是进程对上面的某一个进程右键结束任务就杀死了某个进程。 在Linux中通过ps ajx可以查看所有的进程。 这些进程都有自己的名字和编号。 top命令查看正在运行的进程。 现在在Linux中写一段代码 #include iostream
#include unistd.hint main()
{while (true){std::cout This is a process. std::endl;sleep(1);}return 0;
} 在运行这段代码之后输入指令查看进程。 一个名为proc的程序是保存在磁盘当中的在计算机开机的时候操作系统一定是预先加载到内存中的。如果我想把proc运行根据冯诺依曼结构这个proc一定会先加载到内存中是数据的部分交给控制器是二进制的部分交给运算器去执行。 但是一个操作系统可以同时运行多个进程那么操作系统中可能会存在刚打开的进程正在运行的进程即将结束的进程所以操作系统要将这些进程进行管理起来。要想管理得先让操作系统认识这些进程也就是先描述起来然后对这些进程进程管理也就是组织。 描述进程 任何一个进程在加载到内存的时候形成真正的进程时操作系统要先创建描述进程的结构体对象---PCB Process Ctrl Block(进程控制块) 那么PCB是什么呢 要想认识某个事物就要先知道它的属性比如说三边长度一样的封闭图形等。当属性堆积的够多的时候这些属性集合起来就是目标对象。 所以描述进程就是将最常用的属性放在一起。PCB就是进程属性的集合。 而进程就是PCB程序和数据组成的。 PCB的内容 信息 含义 进程标识符 表明系统中的各个进程 状态 说明进程当前的状态 位置信息 指名程序及数据在主存或外存的物理位置 状态信息 参数信号量消息等 队列指针 链接同一状态的进程 优先级 进程调度的依据 现场保护区 将处理机的现场保护到该区域以便再次调度时能继续正确运行 其他 因不同的系统而异 程序程序部分描述了进程需要完成的功能。 数据数据部分包括程序执行时所需的数据及工作区该部分只能为一个进程所专用是进程的可修改部分。 所以将程序加载到内存中不光光是把代码和数据放到操作系统中还会创建用来描述这个程序的PCB对象。 PCB中存在指针信息用来找到自己的代码和数据。 系统当中不会只有一个进程会有多个进程。这些进程加载到内存中在创建PCB对象PCB中存在指针通过指针再将所有的进程的PCB链接在一块在通过PCB中的指针找到自己的代码和数据。这样在操作系统中对进程的管理就变成了对单链表进行增删查改 上面所描述的是所有操作系统的原理但是具体的操作系统会有差别。 那么Linux操作系统是怎么做的 在Linux操作系统下的PCB是 tack_struct tack_struct是Linux内核的一种数据结构它会被装载到RAM(内存)里并且包含着进程的信息 task_struct内容分类 跟上面的PCB的组成一样。 PCB - tack_struct 结构体里面包含进程的所有属性。 Linux中如何组织进程Linux内核中最基本的组织进程tack_struct的方式是采用双向链表组织的。 但这并不是存粹的双链表可能task_struct中存在指针指向一个队列一棵树等其他数据结构中。Linux中数据结构的关系一定是复杂的。 对tack_struct的管理就是放在某个组织的数据结构中这个进程要等待放在等待队列里要运行放在运行队列里所以这个进程要怎么工作就放在哪一个在组织的数据结构中。 ps ajx | head -1 ps ajx | grep ./proc通过这个命令就可以查看我们刚刚执行的那个名为proc的程序的进程 也可以通过 proc去查看。ls /proc 这个目录会在关机的时候全部关闭再开机的时候再打开。 这些蓝色的都是目录在这里都是以PID(唯一标识符)的形式表示的 ./proc的PID是9965既然蓝色的是目录说明就可以进入到这个目录中查看一些信息。 当我ctrlc结束这个进程的时候再次查看这个进程就会找不到。如果再次启动这个进程PID就会发生变化。 第二个gerp.../proc的进程是grep ./proc的进程因为进行过滤的时候系统创建出了这个进程。 这个exe文件是一个链接文件指向正在运行的名为proc的进程。 cwd是当前进程的工作目录。 再使用 touch命令的时候直接再某一个目录上 touch为什么能够直接创建出文件而不用先输入路径呢因为再使用 touch命令的时候系统自动创建进程进程中的cwd会自动记录当前目录的路径。再创建的时候自动的把cwd拼接到要创建的文件名前面。 cwd/FileName 通过系统调用获取进程标识符 每个进程要被管理就必须有一个唯一的标识符---PID COMMAND代表进程执行的时候是什么命令。 那么这个PID有什么命令呢 现在我写了一个死循环 代码再不停的打印Hello World我通过命令查看这个进程的PID 然后现在我要杀死这个进程 kill -9 PID 查到某个进程的PID然后kill可以直接干掉。 如何查询自己的PID呢 通过getpid函数可以. #include iostream
#include unistd.hint main()
{while (true){std::cout I am getpid() std::endl;std::cout Parent am getppid() std::endl;}return 0;
} PID是自己本身的PPID是父进程的PID。 这个程序我执行了两次PID一直在变PPID却没有变化这个PPID是什么呢 当我们执行程序的时候bash会给我们创建进程。我们再命令行中输入的所有指令都是bash进程的子进程。 通过系统调用创建进程-fork 如果我们自己想创建进程fork可以完成 根据这个返回值来看这个函数有两个返回值 #include unistd.h
#include stdio.h int main()
{printf(begin:This is a process. pid:%d,ppid:%d,getpid(),getppid());pid_t id fork();if (id 0){while (true){printf(This is a child process. pid:%d,ppid:%d,getpid(),getppid()); sleep(1); } } else if (id 0) { while (true) { printf(This is a person process. pid:%d,ppid:%d,getpid(),getppid()); sleep(1); } } else { printf(error);}else {std::cout error std::endl;}return 0;
} 按照我们以前写的程序只要第一个if条件满足就不会再执行其他的分支语句了。 这个代码再循环打印子进程和父进程中的内容一份代码中跑了两个死循环再之前是不可能实现的但是有了fork就可以了因为变成了两个进程--父进程和子进程。 父进程的pid是3870子进程的ppid也是3870说明这两个进程之间的关系是父子。 这个2592就是bash 说明父进程是通过bash来创建的。 上面的代码执行到fork的时候创建出了子进程。 代码是从上往下执行的执行到fork函数的时候整个代码就会变成两个执行流一个进入到fork大于0的代码中一个进入到fork0的代码中。这是能跑两个代码的原因。 为什么fork要给子进程返回0给父进程返回子进程pid 一般而言fork之后的代码父子共享。返回不同的返回值是为了区分让不同的执行流执行不同的代码块。 一个函数是如何做到返回两次的 fork是一个函数函数有自己的实现方法它本身是在操作系统中有自己的实现。 return也是代码父进程执行到return的时候会返回一次子进程执行到return的时候也会返回一次所以就返回了两次。 fork有两个返回值那么一个id变量怎么会有两个值呢 父进程在执行的时候会有自己的代码和数据这个代码是和子进程共享的数据呢父进程有自己的数据的子进程也应该有自己的数据。进程之间是有独立性的一个进程崩了不会影响另一个进程。所以子进程要想办法把父进程的数据拷贝一份拷贝一份各有各的数据但是子进程也有可能不会对一些数据进行访问没用的数据也进行拷贝会造成浪费。子进程要访问父进程中的数据可以对要修改的数据进行拷贝改多少申请多少空间这种技术是数据层面的写时拷贝。如果没有更改父子进程的代码和数据共享。 上面说过进程PCB代码和数据。创建子进程就是系统中多了一个进程。父进程中的PCB存在指针指向代码和数据而子进程中也会存在指针指向代码和数据父子进程中的代码是共享的。fork之后父子进程代码共享但是可以做不同的事情。 fork之后父子进程谁先运行呢 这个是由调度器决定的。 进程状态 CPU只有一个的情况下存在多个进程这些进程要竞争CPU的资源这些资源要合理的分配所以CPU要维护一个运行队列(struct runqueue)这些进程要想运行要先链接到运行队列当中因为PCB本来就是数据结构对象运行队列中的头指针指向PCB尾指针指向最后一个PCB。这个时候CPU要运行进程直接在运行队列中找到一个进程放到CPU中运行即可。 凡是处于运行队列中的进程都属于运行状态 当一个进程在运行时则该进程处于运行态 这个时候你在创建一个进程这个进程想要执行链接在队列中即可。 那么一个进程只要把自己放到CPU上开始运行了是不是一直要执行完毕才把自己放下来 不是的比如平常写代码的时候我们写了一个死循环但是其他程序还能正常运行。每一个进程都有一个叫做时间片的概念一旦运行时间超过时间片这个进程就会重新去排队CPU运行新的进程所以在一段时间内所有进程代码都会被执行。也可以称为并发执行。 在操作系统中底层存在各种各样的硬件。操作系统可以管理软硬件资源。这些硬件虽然都不同但他们都可以用结构体对象来表示。 struct dev
{int type;int status;struct task_struct *head;....
} 将这些结构体在链接起来这样就可用数据结构来管理这些硬件了。 现在我们写了一个带 std::cin的程序运行以后设备要从键盘当中读取数据但是这个时候我们不输入此时这个进程就要等待从键盘上获取数据那么这个队列就不能放在运行队列中会放在等待队列(waitqueue)当中直到从键盘上获取了数据。获取了数据之后就会放到运行队列当中。 所以这种在等待特定设备的进程叫做阻塞状态。 一个进程正在等待某一件事发生(例如请求I/O等待I/O完成等)而暂时停止运行 挂起是一个比较奇怪的概念。 假如现在有一个设备叫做磁盘如果今天有多个进程正在等待键盘资源这时操作系统内部的内存资源严重不足了操作系统会在保证正常的情况下省出来内存资源一些在等待队列当中的资源没有被CPU调用这些进程处于空闲状态此时操作系统会将这些进程的PCB保留代码和数据会放到外设当中这个过程叫做换出PCB在等待队列中排队等到这个进程就绪了在把代码和数据从外设中拿出来放到运行队列当中这个过程叫做换入。其中一个进程只有PCB在代码和数据被换出了此时这个进程的状态就是挂起状态这样就给以给操作系统省出资源。 Linux中的进程状态 /*
* 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 */
}; R运行状态running : 并不意味着进程一定在运行中它表明进程要么是在运行中要么在运行队列里。
S睡眠状态sleeping): 意味着进程在等待事件完成这里的睡眠有时候也叫做可中断睡眠interruptible sleep。
D磁盘休眠状态Disk sleep有时候也叫不可中断睡眠状态uninterruptible sleep在这个状态的进程通常会等待IO的结束。
T停止状态stopped 可以通过发送 SIGSTOP 信号给进程来停止T进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
X死亡状态dead这个状态只是一个返回状态你不会在任务列表里看到这个状态
僵死状态Zombies是一个比较特殊的状态。当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵尸进程。僵死进程会以终止状态保持在进程表中并且会一直在等待父进程读取退出状态代码。所以只要子进程退出父进程还在运行但父进程没有读取子进程状态子进程进入Z状态 下面我们创建一个名为myproc.cpp的文件。 #include iostream
#include unistd.h int main()
{ while (true) { std::cout Hello World std::endl; sleep(1); } return 0;
} 运行这个进程之后在查看进程。 发现这个进程是S状态myproc不是在运行吗为什么会是S状态。 现在把代码中的输出和sleep给去了。 此时就变成了R状态。 第一次的代码带有 std::cout 看似代码一直在打印其实是阻塞状态当我把输出给去了就变成了运行态(R)。 R的意思是前台运行在运行的时候给 ./myproc后面加上 ./myproc 就变成后台运行。 #include iostream
#include unistd.h int main()
{ std::cout cin:; int a 0; std::cin a; std::cout echo: a std::endl; return 0;
} 在运行这个程序的时候如果没有输入界面就会一直卡在这里等待着输入。 查看进程 我并没有输入所以这个进程一直在等待直到获取到相应的资源后才可以运行这就是S状态。所谓的阻塞就是在等待资源。 当获取了资源后就是R状态了。 如果一个进程处于D状态在Linux中也是阻塞状态也是深度睡眠。 现在有一个进程这个进程在向磁盘写入1G的数据磁盘把数据接收后存在某一区域这个过程是要花时间的在这期间进程就要进行等待。完成这个操作后磁盘向进程发起反馈不管成功与否。那么在磁盘写入的时候这个进程被操作系统强制干了但是磁盘要向进程进行反馈的时候却找不到进程了。这个数据若不重要丢掉也无所谓如果数据非常重要呢丢失了就会造成大问题。所以让进程在等待磁盘写入完毕期间这个进程不能被任何人干掉不就行了。进程在等待磁盘写入期间就是D状态---disk sleep t状态被称为暂停状态。 #include iostream
#include unistd.h int main()
{while (true) { std::cout Hello World std::endl; sleep(1); } return 0; } 运行之后进程处于S状态 通过kill -l可以查看更多的信号之前用过kill -9 PID的命令用来杀死进程。 18和19信号分别是继续和暂停信号。 kill -19 PID 在输入 kill -18 PID X是死亡状态。 进程终止了就要把资源进行回收这只是一个返回状态不会再任务列表里看到这个状态。 Z状态也是僵尸状态。 一个进程死掉了并不会直接进行回收而是先将进程的退出信息维持一段时间让关心这个进程的人知道结果和原因。维护信息的这个状态是Z状态。 一个进程中父进程最关心儿子进程的信息。如果父进程没有关心儿子进程操作系统就会一直维持着儿子进程的信息。 #include iostream
#include unistd.h
#include cstdlibint main()
{pid_t id fork();if (id 0){int cnt 5;while (cnt){std::cout 我是子进程,pid getpid() ppid getppid() std::endl;cnt--;sleep(1);}exit(0);}else {while (true){std::cout 我是父进程,pid getpid() ppid getppid() std::endl;sleep(1);}}return 0;
} 这个代码中父进程并没有对子进程干任何事情子进程结束之后父进程就看着啥也不干。 当运行这个程序的时候cnt为0前一直是都是S状态cnt为0后父进程是S状态子进程变成了Z状态既僵尸状态。 进程一般退出的时候如果父进程没有主动回收子进程信息子进程会一直让自己处于Z状态。进程的相关资源尤其是task_struct 结构体不能被释放。僵尸进程会一直占用自身资源。僵尸进程不予回收就会造成内存泄漏问题。 那么我们把myproc给结束之后为什么不会变成僵尸进程因为bash会对myproc负责。爹只对儿子负责。 myproc结束没有变成僵尸进程是因为bash会负责那子进程为什么会没了bash可不会对孙子负责。 现在不让子进程退出让父进程退出。 #include iostream
#include unistd.h
#include cstdlibint main()
{pid_t id fork();if (id 0){int cnt 500;while (cnt){std::cout 我是子进程,pid getpid() ppid getppid() std::endl;cnt--;sleep(1);}exit(0);}else {int cnt 5;while (cnt){std::cout 我是父进程,pid getpid() ppid getppid() std::endl;cnt--;sleep(1);}}return 0;
} 原来子进程的父进程的PID是15604父进程退出之后变成了1。 如果父进程先退出子进程的父进程会被改变成1号进程(操作系统) 父进程是1号进程---孤儿进程该进程被系统领养。 父进程结束了孤儿进程退出后它的信息就没有人关心了。只能有操作系统来领养。 所以上面子进程是僵尸进程将父进程结束后子进程由操作系统领养所以子进程也会结束。 僵尸进程的危害 进程的退出状态必须被维持下去因为他要告诉关心它的进程父进程你交给我的任务我办的怎么样了。可父进程如果一直不读取那子进程就一直处于Z状态。维护退出状态本身就是要用数据维护也属于进程基本信息所以保存在task_struct(PCB)中换句话说 Z状态一直不退出 PCB一直都要维护那一个父进程创建了很多子进程就是不回收就会造成内存资源的浪费。因为数据结构对象本身就要占用内存想想C中定义一个结构体变量对象是要在内存的某个位置进行开辟空间。内存泄漏 进程优先级 cpu资源分配的先后顺序就是指进程的优先权priority。优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用可能改善系统性能。还可以把进程运行到指定的CPU上这样一来把不重要的进程安排到某个CPU可以大大改善系统整体性能 优先级是对于资源的访问谁先访问谁后访问。就好比买饭的时候要排队我们已经进入了餐厅有吃饭的权限排队就是决定谁先吃谁后吃的问题。 为什么会有优先级呢 学生在学校要吃饭如果给每个学生配一个厨师那就不需要在餐厅排队吃饭了。但学生这么多不可能实现每个学生配一个厨师。一个系统中有好多进程这些进程不可能都配一个CPU且资源是有限的所以这些进程就需要对CPU进行竞争。操作系统必须保证大家良性竞争就要确认优先级。如果不保证良性竞争那结果就是谁nb谁资源多这样会造成一些进程长时间得不到CPU资源该进程的代码长时间无法得到推进---该进程的饥饿问题。 当然不要去修改优先级调度器会自己解决优先级的问题。 #include iostream
#include unistd.hint main()
{while (true){std::cout This is a process. std::endl;sleep(1);}return 0;
} 运行之后查看进程 ps -al PRI就是优先级(priority) NI就是nice值进程优先级的修正数据。 PRI也还是比较好理解的即进程的优先级或者通俗点说就是程序被CPU执行的先后顺序此值越小进程的优先级别越高
那NI呢?就是我们所要说的nice值了其表示进程可被执行的优先级的修正数值
PRI值越小越快被执行那么加入nice值后将会使得PRI变为 PRI(new)PRI(old)nice
这样当nice值为负值的时候那么该程序将会优先级值将变小即其优先级会变高则其越快被执行所以调整进程优先级在Linux下就是调整进程nice值
nice其取值范围是-20至19一共40个级别 Linux不会让你随便的调整优先级所以nice值给出的有限制。 需要强调一点的是进程的nice值不是进程的优先级他们不是一个概念但是进程nice值会影响到进程的优先级变化。可以理解nice值是进程优先级的修正修正数据 如何更改优先级呢 top命令。 然后输入r 在输入PID 在输入新的nice值 就可以完成修改了。 如果新的nice值不在ni的区间系统会自动的找在区间内的最大值。 那么操作系统是如何根据优先级开展的调度呢 通过位图。可以近乎O(1)的时间复杂度来调度。 其他概念 竞争性: 系统进程数目众多而CPU资源只有少量甚至1个所以进程之间是具有竞争属性的。为了高效完成任务更合理竞争相关资源便具有了优先级
独立性: 多进程运行需要独享各种资源多进程运行期间互不干扰
并行: 多个进程在多个CPU下分别同时进行运行这称之为并行
并发: 多个进程在一个CPU下采用进程切换的方式在一段时间之内让多个进程都得以推进称之为并发 环境变量 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数如我们在编写C/C代码的时候在链接的时候从来不知道我们的所链接的动态静态库在哪里但是照样可以链接成功生成可执行程序原因就是有相关环境变量帮助编译器进行查找。环境变量通常具有某些特殊用途还有在系统当中通常具有全局特性 。 我们写的代码在编译后要运行的时候需要带 ./才能运行。而指令则不需要带 ./就可以运行指令和我们写的代码都在目录中这些目录还有什么区别吗 系统当中针对于指令的搜索Linux会提供一个环境变量PATH。 通过 echo $PATH可以打印环境变量 这些路径以冒号为分隔符在执行指令的时候系统会在上面的路径中寻找指令。所以我们自己写的代码只写文件名系统在路径中搜索不到也就无法运行了。 那么将这个proc的路径添加到PATH中是不是就可以输入名字运行代码了呢 这样的写法是覆盖PATH会将之前的路径都覆盖。在使用了之后绝大部分指令就不能运行了。因为系统找不到对应的路径。就算覆盖了不用担心PAHT会在启动的时候加载到内存重启一下就会恢复。 将路径添加到PATH后就可以输名字运行代码了。 输入 env可以查看环境变量。 我们在终端输入指令的时候会自动的记录上一条输入的指令这个记录的指令是有限制的HISTSIZE就是能够记录的条数 USER代表的用户。 PWD代表当前路径 通过getenv函数可以获取环境变量。 #include iostream #include string #include stdlib.h int main() { std::string who getenv(USER); if (who root) { std::cout 允许做任何事情 std::endl; } else { std::cout 你就一个普通用户没有足够权限 std::endl; } return 0; } 环境变量是系统提供的一组namevalue形式的变量不同的环境变量有不同的用户通常具有全局属性。 命令行参数 在学C语言的时候一些教材上main函数是带参数的。 int main(int argc, char *argv[])
{} C/C的main函数是可以传参的上面两个就是参数。 #include stdlib.h
#include stdio.h int main(int argc,char *argv[])
{ for (int i 0; i argc; i) { printf(argv[%d]-%s,i,argv[i]); } return 0;
} 当我们运行代码的时候 你以为你输入的是 ./proc -a -b -c开始做命令行解释的时候会把这个字符串打散成四个字符串再将每个字符串的起始地址保存在argv中然后传递给main函数argc中存数量argv中存的字符串。 为什么要这么做呢 #include stdlib.h
#include string.h
#include stdio.hint main(int argc, char *argv[])
{if (argc ! 2){printf(Usage: %s -[a|b|c|d]\n,argv[0]);}if (strcmp(argv[1],-a) 0){printf(aaa\n);}else if (strcmp(argv[1],-b) 0){printf(bbb\n);}else if (strcmp(argv[1],-c) 0){printf(ccc\n);}else if (strcmp(argv[1],-d) 0){printf(ddd\n);}else {printf(defaul\n);}return 0;
} 同一个指令不同的选项可以得到不同的结果。 这样可以为指令工具软件等提供命令行选项的支持。比如 ls -a,ps ajx等。 还可以带第三个参数---环境变量列表。 int main(int argc,char *argv[],char *env[])
{} 我们所运行的进程都是子进程bash本身在启动的时候会从操作系统的配置文件中读取环境变量信息子进程会继承父进程交给我的环境变量。 怎么证明这件事 在命令行上这样搞并不是环境变量但确实存在。 这是本地变量。 所谓的本地变量就是在命令行中定义变量。本地变量不会被继承 a 1 b 2 c 3 echo $a可以输出a。但如果敲一个代码看这个变量是无法找到的echo却可以输出。 两批命令 常规命令通过创建子进程完成的。 内建命令bash不创建子进程而是由自己亲自执行类似于bash调用了自己写的或者系统提供的函数。 set命令可以查看系统当中的所有变量。 现在将这个变量定义为环境变量。 只需要带个export将它导出即可。 在运行代码后发现会继承。 unsert MY_VALUE会取消环境变量。