冯诺依曼与进程【Linux】

冯诺依曼体系结构(从硬件的角度描述)

在这里插入图片描述

.冯诺依曼体系结构中的存储器指的是内存

外设:简单理解为除了内存和CPU,其他全是外设
输入设备:鼠标,键盘,摄像头,话筒,磁盘,网卡…
输出设备:显示器,播放器硬件,磁盘,网卡…

磁盘驱动器既能将存储在磁盘上的信息读进内存中,又能将内存中的信息写到磁盘上。因此,就认为它既是输入设备,又是输出设备

CPU:
运算器:对我们的数据进行计算任务(算数运算,逻辑运算)
控制器:对我们的计算硬件流程进行一定的控制

CPU在读取和写入的时候,在数据层面,只和内存打交道,不和外设直接沟通,这样有利于提高整个计算机的运行效率

磁盘上的文件程序想要运行,必须要加载到内存里面,因为CPU只能从内存中访问你写的数据和代码,我们平常所进行的编程其实就是在为CPU准备数据和代码,等CPU过来读取这些代码并执行他,这些都是冯诺依曼体系结构所决定的

冯诺依曼体系结构(从软件的角度描述)

已发送qq信息为例,不考虑网络

在这里插入图片描述

各自都打开了QQ程序,并将QQ这个程序加载到了内存里面,CPU会执行QQ程序的代码,消息数据会由输入设备键盘加载到内存中的QQ程序里,CPU对这些消息做出处理,将处理后的结果返回给内存,这些消息会从内存进一步加载到外部设备网卡和显示器等
,笔记本B的网卡会接收这些消息,并将这些消息加载到他的内存中的QQ程序,然后CPU做出信息的分析将结果返回到内存里面,最后这些处理过后的信息会进一步加载到笔记本B上的显示器中,这样就完成了信息的发送和接收等。

操作系统(软件)

操作系统是一个进行软硬件资源管理的软件

操作系统包括进程管理,内存管理,文件系统,驱动管理,这些都是操作系统对于软件的管理,除了管理这些,操作系统还承担管理冯诺依曼硬件体系结构。

为什么操作系统要进行管理呢?
操作系统可以通过合理的对于软硬件资源管理(手段),来为用户提供良好的(稳定的、安全的、高效的)执行环境

操作系统里面,里面会有各种数据。可是,操作系统不相信任何用户!
操作系统为了保证自己数据安全,也为了保证给用户能够提供服务,操作系统以接口的方式给用户提供调用的入口。来获取操作系统内部的数据

接口是操作系统提供的用C实现的,自己内部的函数调用–—系统调用
所有访问操作系统的行为,都只能通过系统调用完成

理解管理

管理者和被管理者是不需要见面的

管理者在不见被管理者的情况下,如何做好的管理呢?
只要能够得到管理信息,就可以在未来进行管理决策
管理的本质:是通过对数据的管理,达到对人的管理

管理者和被管理者面都不见,如何拿到对应的数据?
通过执行者

在操作系统中,管理任何对象,最终都可以转化成为对某种数据结构的增删查改

系统调用和库函数

在开发角度,操作系统对外会表现为一个整体,但是会暴露自己的部分接口,供上层开发使用,这部分由操作系统提供的接口,叫做系统调用接口。

系统调用在使用上,功能比较基础,对用户的要求相对也比较高,开发者对部分系统调用进行封装,从而形成库,有了库,就利于上层用户或者开发者进行二次开发,C/C++库其实就是系统调用接口封装得来的,所以系统调用和库函数是上下层 和被调用之间的关系
在这里插入图片描述

进程

一个已经加载到内存中的程序,叫做进程(任务)
正在运行的程序,叫做进程

操作系统必须的将进程管理起来
如何管理进程?
任何一个进程,在加载到内存的时候,形成真正的进程时,操作系统要先创建描述进程的结构体对象——PCB(process control block)

管理的逻辑是先描述,再组织。在Linux中,操作系统会通过task_struct结构体,将每一个进程的所有属性抽象化描述起来,Linux操作系统再通过双向循环链表的数据结构将数量庞大的进程进行组织,这样,管理进程就变成了对进程所对应的PCB进行相关的管理

进程 = 内核PCB数据结构对象(描述该进程所有的属性值)+ 你自己的代码和数据
你自己的代码和数据就是在磁盘中形成的可执行程序

在这里插入图片描述

查看进程的两种方式

ps指令

[cxq@VM-4-10-centos lesson10]$ ps ajx | head -1 && ps ajx | grep myprocess
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
17234 17444 17444 17234 pts/1    17444 S+    1002   0:00 ./myprocess
15982 19707 19706 15982 pts/0    19706 S+    1002   0:00 grep --color=auto myproces

ppid 父进程id,pid是进程id,pgid是进程组id,sid会话id,TTY终端,STAT状态,uid用户id,COMMAND代表哪个进程

ls指令
根目录下的proc目录来查看进程,进程也可以被当作一个目录,Linux下一切皆文件

[cxq@VM-4-10-centos lesson10]$ ls /proc
1      14855  21151  273    49    8            ioports       sched_debug
10     15904  21295  28     50    9            irq           schedstat
1009   15980  21506  29     51    acpi         kallsyms      scsi
102    15982  22     293    52    buddyinfo    kcore         self
1074   16     22719  294    527   bus          keys          slabinfo
1076   16348  23     301    587   cgroups      key-users     softirqs
1077   16357  23018  31796  589   cmdline      kmsg          stat
11     16358  24     36     6     consoles     kpagecount    swaps
12     17229  2482   37     607   cpuinfo      kpageflags    sys
1244   17232  2491   38     608   crypto       loadavg       sysrq-trigger
1257   17234  25     389    613   devices      locks         sysvipc
12575  1734   256    39     619   diskstats    mdstat        timer_list
1259   17444  2563   4      620   dma          meminfo       timer_stats
1267   18     26     413    621   driver       misc          tty
1268   18323  264    414    622   execdomains  modules       uptime
13     19     265    4282   623   fb           mounts        version
13349  2      267    4669   624   filesystems  mtrr          vmallocinfo
14     20     268    4676   65    fs           net           vmstat
14377  201    269    47     7     interrupts   pagetypeinfo  xpmem
14735  21     27     4752   7000  iomem        partitions    zoneinfo

查看进程17444

[cxq@VM-4-10-centos lesson10]$ ls /proc/17444 -dl
dr-xr-xr-x 9 cxq cxq 0 Nov  6 14:21 /proc/17444
[cxq@VM-4-10-centos lesson10]$ ls /proc/17444
attr             cwd       map_files   oom_adj        schedstat  task
autogroup        environ   maps        oom_score      sessionid  timers
auxv             exe       mem         oom_score_adj  setgroups  uid_map
cgroup           fd        mountinfo   pagemap        smaps      wchan
clear_refs       fdinfo    mounts      patch_state    stack
cmdline          gid_map   mountstats  personality    stat
comm             io        net         projid_map     statm
coredump_filter  limits    ns          root           status
cpuset           loginuid  numa_maps   sched          syscall


查看进程26670

[cxq@VM-4-10-centos lesson10]$ ls /proc/26670 -l
total 0
dr-xr-xr-x 2 cxq cxq 0 Nov  6 14:55 attr
-rw-r--r-- 1 cxq cxq 0 Nov  6 14:55 autogroup
-r-------- 1 cxq cxq 0 Nov  6 14:55 auxv
-r--r--r-- 1 cxq cxq 0 Nov  6 14:55 cgroup
--w------- 1 cxq cxq 0 Nov  6 14:55 clear_refs
-r--r--r-- 1 cxq cxq 0 Nov  6 14:54 cmdline
-rw-r--r-- 1 cxq cxq 0 Nov  6 14:55 comm
-rw-r--r-- 1 cxq cxq 0 Nov  6 14:55 coredump_filter
-r--r--r-- 1 cxq cxq 0 Nov  6 14:55 cpuset
lrwxrwxrwx 1 cxq cxq 0 Nov  6 14:54 cwd -> /home/cxq/108/lesson10
-r-------- 1 cxq cxq 0 Nov  6 14:54 environ
lrwxrwxrwx 1 cxq cxq 0 Nov  6 14:54 exe -> /home/cxq/108/lesson10/myprocess
dr-x------ 2 cxq cxq 0 Nov  6 14:55 fd
dr-x------ 2 cxq cxq 0 Nov  6 14:55 fdinfo
-rw-r--r-- 1 cxq cxq 0 Nov  6 14:55 gid_map
-r-------- 1 cxq cxq 0 Nov  6 14:55 io
-r--r--r-- 1 cxq cxq 0 Nov  6 14:55 limits
-rw-r--r-- 1 cxq cxq 0 Nov  6 14:55 loginuid
dr-x------ 2 cxq cxq 0 Nov  6 14:55 map_files
-r--r--r-- 1 cxq cxq 0 Nov  6 14:55 maps
-rw------- 1 cxq cxq 0 Nov  6 14:55 mem
-r--r--r-- 1 cxq cxq 0 Nov  6 14:55 mountinfo
-r--r--r-- 1 cxq cxq 0 Nov  6 14:55 mounts
-r-------- 1 cxq cxq 0 Nov  6 14:55 mountstats
dr-xr-xr-x 5 cxq cxq 0 Nov  6 14:55 net
dr-x--x--x 2 cxq cxq 0 Nov  6 14:55 ns
-r--r--r-- 1 cxq cxq 0 Nov  6 14:55 numa_maps
-rw-r--r-- 1 cxq cxq 0 Nov  6 14:55 oom_adj
-r--r--r-- 1 cxq cxq 0 Nov  6 14:55 oom_score
-rw-r--r-- 1 cxq cxq 0 Nov  6 14:55 oom_score_adj
-r--r--r-- 1 cxq cxq 0 Nov  6 14:55 pagemap
-r-------- 1 cxq cxq 0 Nov  6 14:55 patch_state
-r--r--r-- 1 cxq cxq 0 Nov  6 14:55 personality
-rw-r--r-- 1 cxq cxq 0 Nov  6 14:55 projid_map
lrwxrwxrwx 1 cxq cxq 0 Nov  6 14:54 root -> /
-rw-r--r-- 1 cxq cxq 0 Nov  6 14:55 sched
-r--r--r-- 1 cxq cxq 0 Nov  6 14:55 schedstat
-r--r--r-- 1 cxq cxq 0 Nov  6 14:55 sessionid
-rw-r--r-- 1 cxq cxq 0 Nov  6 14:55 setgroups
-r--r--r-- 1 cxq cxq 0 Nov  6 14:55 smaps
-r--r--r-- 1 cxq cxq 0 Nov  6 14:55 stack
-r--r--r-- 1 cxq cxq 0 Nov  6 14:55 stat
-r--r--r-- 1 cxq cxq 0 Nov  6 14:55 statm
-r--r--r-- 1 cxq cxq 0 Nov  6 14:55 status
-r--r--r-- 1 cxq cxq 0 Nov  6 14:55 syscall
dr-xr-xr-x 3 cxq cxq 0 Nov  6 14:55 task
-r--r--r-- 1 cxq cxq 0 Nov  6 14:55 timers
-rw-r--r-- 1 cxq cxq 0 Nov  6 14:55 uid_map
-r--r--r-- 1 cxq cxq 0 Nov  6 14:55 wchan

对cwd的理解

[cxq@VM-4-10-centos lesson10]$ ll
total 20
-rw-rw-r-- 1 cxq cxq    0 Nov  6 15:02 log.txt
-rw-rw-r-- 1 cxq cxq   75 Nov  3 14:10 Makefile
-rwxrwxr-x 1 cxq cxq 8464 Nov  6 15:02 myprocess
-rw-rw-r-- 1 cxq cxq  157 Nov  6 15:02 myprocess.c

在这里插入图片描述

在这里插入图片描述

进程在启动时有自己的工作目录,在调fopen时,默认将cwd这个路径拼接到log.txt前面,所以最终创建的文件就在当前进程所在的目录

** kill命令**

[cxq@VM-4-10-centos lesson11]$ ps ajx | head -1 &&  ps ajx | grep proc | grep -v grep
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
10576 15817 15817 10576 pts/1    15817 S+    1002   0:00 ./proc
[cxq@VM-4-10-centos lesson11]$ kill -9 15817

通过系统调用获取进程的PID和PPID

使用系统调用函数,getpid和getppid即可分别获取进程的PID和PPID。

在这里插入图片描述

在这里插入图片描述

关于bash: 每次登录xshell 时,系统会为我们单独创建一个bash进程 ,我们在命令行中输入的指令都是bash进程的子进程 ,这些指令的父进程就是bash, bash进程只负责命令行的解释 ,具体出问题,只会影响bash的子进程,并不会影响bash,这也解释了为什么父进程一直不变的原因

通过系统调用创建进程- fork

在这里插入图片描述

fork功能是创建一个子进程
在这里插入图片描述
在这里插入图片描述

根据上述代码得出三个问题
1、为什么需要创建子进程

为了让父和子执行不同的事情,需要想办法让父和子执行不同的代码块

2、为什么fork要给子进程返回0,给父进程返回子进程pid?
代码是不能被修改的,能修改的是数据
fork之后,父子代码共享(返回不同的返回值,是为了区分让不同的执行流,执行不同的代码块) ,
代码不会被修改,可以让父进程和子进程共享同一份数据
,这样父进程是不会影响到子进程的。

数据可能被修改,当子进程需要访问父进程的某一部分数据,操作系统识别到子进程会对这部分数据进行修改,操作系统会在内存中重新开辟一块空间,将父进程的需要修改的数据拷贝到新开辟的空间中 ,让子进程对该空间进行修改 ,这样就不会影响父进程的数据 ,这种操作是数据层面的写时拷贝

父进程返回子进程pid, 为了明确父进程控制哪一个子进程(取决于pid)
子进程只需要调用getpid() ,能直接获取进程的pid,返回值为0标识成功即可

3、一个函数是如何做到返回两次的?

fork在执行的时候经历了
1、创建子进程PCB
2、填充PCB对应的内容
3、让子进程和父进程指向同样的代码
4父子进程都是有独立的task_struct,可以被CPU调度运行了

通过观察上述代码 ,id变量是父进程的数据 , 当fork函数内部执行完毕,父子进程分别被调度, return两次 , 父子进程创建时 ,代码是共享的 ,所以return也是共享的, 父进程return 写入 , 子进程return写入,此时子进程发生了写时拷贝,操作系统对同一份id变量拷贝了两份 ,所以看到的id值就会有两个

4、一个变量怎么会有不同的内容?
任何平台,进程在运行的时候,是具有独立性的
在这里插入图片描述
5、如果父子进程被创建好,fork执行后,谁先运行?

由调度器决定,是不确定的

Linux进程状态

Linux操作系统的源代码当中对于进程状态有如下定义

static const char *task_state_array[] = {
	"R (running)",       /*  0*/
    "S (sleeping)",      /*  1*/
    "D (disk sleep)",    /*  2*/
    "T (stopped)",       /*  4*/
    "T (tracing stop)",  /*  8*/
    "Z (zombie)",        /* 16*/
    "X (dead)"           /* 32*/
};

运行、阻塞、挂起状态

一个CPU匹配一个运行队列

让进程入队列,等待CPU资源。本质:将该进程的task_struct结构体对象放入CPU的运行队列struct runqueue中。操作系统操作的不是加载到内存中的程序,操作的是进程对应的PCB(进程控制块,内核数据结构)

运行状态-R(running)

一个进程处于运行状态,表明一个进程要么在运行中,要么在运行队列里。也就是说,可以同时存在多个R状态的进程

在这里插入图片描述

所有处于运行状态,即可被调度的进程,都被放到运行队列当中,当操作系统需要切换进程运行时,就直接在运行队列中选取进程运行

一个进程只要把自己放到CPU上开始运行了,并不是一直要执行完毕,才把自己放下来

每一个进程都有一个时间片的概念,一个进程在cpu上待的最多的时间

浅度睡眠状态-S (sleeping)

一个进程处于浅度睡眠状态(sleeping),意味着该进程正在等待某件事情的完成,处于浅度睡眠状态的进程随时可以被唤醒,也可以被杀掉(这里的睡眠有时候也可叫做可中断睡眠(interruptible sleep))

在这里插入图片描述

[cxq@VM-4-10-centos lesson12]$ ps aux | head -1 && ps aux |grep proc | grep -v grep

在这里插入图片描述

处于浅度睡眠状态的进程是可以被杀掉的,我们可以使用kill命令将该进程杀掉
在这里插入图片描述

深度睡眠状态-D

深度睡眠也是一种阻塞状态
一个进程处于深度睡眠状态(disk sleep),表示该进程不会被杀掉,即便是操作系统也不行,只有该进程自动唤醒才可以恢复。该状态有时候也叫不可中断睡眠状态(uninterruptible sleep),处于这个状态的进程通常会等待IO的结束。

例:
某一进程要求对磁盘进行写入操作,进程在等待磁盘写入完毕期间,该进程就处于深度睡眠状态,是不会被杀掉的,如果进程当时有写入的任务交给磁盘 ,如果磁盘没有办法立马响应,该进程不能以浅度睡眠的形式存在 ,必须将自己设为深度睡眠状态 ,当磁盘写入完毕 ,进程将D状态恢复成R状态

暂停状态-T

通过发送SIGSTOP信号使进程进入暂停状态,发送SIGCONT信号可以让处于暂停状态的进程继续运行。v

在这里插入图片描述

在这里插入图片描述

对该进程发送SIGCONT信号,该进程就继续运行了。
在这里插入图片描述

阻塞状态

如果一个进程需要scanf读取键盘的数据 ,但是键盘没有输入,此时该进程需要去各自设备的等待队列里等待,我们在等待特定设备的这种进程,称该进程处于阻塞状态

该进程位于等待队列中 ,我们把这种状态叫做阻塞状态

挂起状态

以阻塞状态为例 :

当操作系统内部的内存资源严重不足时,
将位于阻塞状态的进程的PCB保留 ,把对应的代码和数据交换到外设中(换出),例如磁盘中,相当于一个进程只有PCB在排队,当下次资源就绪了,把该进程放入运行队列中,此时再将代码和数据重新换入(换入)

当一个进程的代码和数据被换出了,代码和数据并没有在内存中,我们将该进程称为挂起状态

死亡状态-X

僵尸状态-Z

当一个子进程退出时,他会将自己的状态暂时维持,当父进程读取到了子进程的信息时,子进程才会被释放 ,我们把已经死掉了但是当前需要有父进程来关心,此时这个进程所维持的状态,我们称为僵尸状态

进程一般退出的时候,如果父进程没有主动回收子进程信息,子进程会一直让自己出于Z状态,进程的相关资源,尤其是task struct结构体(PCB)不能被释放

监控脚本

 while :; do ps axj | head -1 && ps axj | grep myproc ;echo ; sleep 1;done

myproc.c的代码
在这里插入图片描述

在这里插入图片描述

僵尸进程

该进程处于僵尸状态。而处于僵尸状态的进程,我们就称之为僵尸进程。
如果父进程不回收僵尸进程,内存会被一直占用 , 直到上层将数据回收 ,在回收之前的时间内会造成内存泄漏
僵尸进程的退出信息被保存在task_struct(PCB)中,如果z状态一直不退出 ,PCB就要一直维护

孤儿进程

在父子进程中,如果父进程先退出,子进程的父进程会被改成1号进程(操作系统),
父进程是1号进程的叫做孤儿进程
该进程被系统领养,后续被操作系统回收

进程优先级

什么是优先级

对于资源的访问,谁先访问,谁后访问

优先级存在的原因?
因为资源是有限的,进程是多个的,注定了,进程之间是竞争关系

操作系统必须保证进程之间良性竞争,确认优先级,如果进程长时间得不到CPU资源,该进程的代码长时间无法得到推进 (进程的饥饿问题)

查看系统进程

ps -l 查看当前终端的进程

[cxq@iZ7xviiy0goapxtblgih6oZ ~]$ ps -l

ps -al 查看用户所启动的进程

[cxq@iZ7xviiy0goapxtblgih6oZ ~]$ ps -al

在这里插入图片描述

[cxq@iZ7xviiy0goapxtblgih6oZ ~]$ ps -al  | head -1 && ps -al |grep myproc 

在这里插入图片描述

在Linux操作系统中,初始进程一般优先级PRI默认为80,NI默认为0

UID:代表执行者的身份。
PID:代表这个进程的代号。
PPID:代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号。
PRI:代表这个进程可被执行的优先级,其值越小越早被执行。
NI:代表这个进程的nice值。

PRI与NI
PRI代表进程的优先级(priority),通俗点说就是进程被CPU执行的先后顺序,该值越小进程的优先级别越高。

NI代表的是nice值,其表示进程可被执行的优先级的修正数值。

PRI值越小越快被执行,当加入nice值后,将会使得PRI变为:PRI(new) = PRI(old) + NI。

若NI值为负值,那么该进程的PRI将变小,即其优先级会变高。

在Linux下,调整进程优先级就是调整进程的nice值。

在Linux操作系统当中,PRI(old)默认为80,即PRI = 80 + NI。

Linux不想过多的让用于参与优先级的调整,在我们对应的范围内进行优先级调整,NI的取值范围是 【-20 , 19】 ,一共40个级别。也就意味着PRI的取值范围是【60,99】

top命令更改进程的nice值
top命令就相当于Windows操作系统中的任务管理器,它能够动态实时的显示系统当中进程的资源占用情况。

使用top命令后按“r”键,会要求你输入待调整nice值的进程的PID。
在这里插入图片描述

输入进程PID并回车后,会要求你输入调整后的nice值。
输入nice值后按“q”即可退出

竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便有了优先级。

独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰。

并行: 多个进程在多个CPU下分别同时进行运行,这称之为并行。

如果计算机存在两个物理CPU,有两个物理CPU,就要维护两个调度队列 ,各自调度各自
此系统中, 在任意一个时刻 ,一定存在两个并行运算的进程

并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发

例:
一段时间内,如果当前进程在CPU上运行,时间片到了之后 ,进程将被剥离下来,另一个进程再上,在一段时间内,这两个进程的代码可以同时推进

假设当前进程在CPU上只占用10ms, 10ms之后 ,如果进程没有跑完 ,将此进程从CPU上剥离下来,继续排队 (基于进程切换基于时间片轮转的调度算法)

环境变量

环境变量是系统提供的一组name=value形式的变量,不同的环境变量﹐有不同的用户,通常具有全局属性

上下文数据: 进程执行时处理器的寄存器中的数据。
cpu内的寄存器里面保存的是进程相关的数据

进程在从CPU上离开的时候,要将自己的上下文数据保存好,甚至带走

进程在被切换的时候:
1、保存上下文
2、恢复上下文

在这里插入图片描述

生成的可执行程序必须要在前面带上./才可以执行?
为什么执行ls命令的时候不用带./就可以执行?

执行一个可执行程序必须要先找到它在哪里,系统能够通过ls名称找到ls的位置系统是不能找到可执行程序的,所以我们必须带上./,以此告诉系统该可执行程序位于当前目录下。

查看环境变量PATH

[cxq@iZ7xviiy0goapxtblgih6oZ lesson12]$ echo $PATH
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/cxq/.local/bin:/home/cxq/bin

系统就是通过环境变量PATH来找到ls命令的
环境变量PATH当中有多条路径,这些路径由冒号隔开,当使用ls命令时,系统就会查看环境变量PATH,然后从左到右依次在各个路径当中进行查找。
ls命令就位于PATH当中的某一个路径下,所以ls命令不带路径执行,系统也是能找到

下面让可执行程序也不用带路径就可以执行

将可执行程序所在的目录导入到环境变量PATH当中

[cxq@iZ7xviiy0goapxtblgih6oZ lesson12]$ PATH=$PATH:/home/cxq/lesson12

在这里插入图片描述
覆盖式修改

[cxq@iZ7xviiy0goapxtblgih6oZ lesson12]$ PATH=/home/cxq/lesson12

在这里插入图片描述

任何一个用户在运行系统登录时都有自己的主工作目录(家目录),环境变量HOME当中即保存的该用户的主工作目

[cxq@iZ7xviiy0goapxtblgih6oZ lesson12]$ echo $HOME
/home/cxq

在Linux当中的各种命令,实际上是由命令行解释器进行解释,而在Linux当中有许多种命令行解释器(例如bash、sh),我们可以通过查看环境变量SHELL来知道自己当前所用的命令行解释器的种类。

[cxq@iZ7xviiy0goapxtblgih6oZ lesson12]$ echo $SHELL
/bin/bash

env:显示所有的环境变量
在这里插入图片描述

在这里插入图片描述

通过系统调用获取环境变量

 #include<stdio.h>
   #include<stdlib.h> 
   int main()
   {
     printf("who : %s\n", getenv( "USER"));
     return 0 ;
     }

在这里插入图片描述

 #include<stdio.h>
   #include<stdlib.h> 
   int main()
   {
     printf("who : %s\n", getenv( "PATH"));
     return 0 ;
     }

在这里插入图片描述

我们所运行的进程,都是子进程,bash本身在启动的时候,会从操作系统的配置文件中读取环境变量信息,子进程会继承父进程的环境变量

export:设置一个新的环境变量

[cxq@iZ7xviiy0goapxtblgih6oZ lesson12]$  export MY_VALUE=12345678

在这里插入图片描述
unset:清除环境变量

[cxq@iZ7xviiy0goapxtblgih6oZ lesson12]$ unset MY_VALUE

在这里插入图片描述

命令行参数

   #include<stdio.h>
   #include<stdlib.h>
   #include<string.h>
   int main(int argc , char * argv[]) //argc是个数 ,argv是指针数组
   {
		   int i =0 ;
		   for( ;i<argc ; i++ )
		   {
		    printf("argv [%d] %s\n",i, argv[i]);                                                               
		  }
  return 0 ; 
  }

命令行参数为指令、工具,软件等提供命令行选项的支持

bash会将./myproc -a认为成 “./myproc -a -b -c”
将这一个大字符串打散成4个字符串 “./myproc” “-a” “-b” “-c” ,此时argc就是4
在这里插入图片描述

每个程序都会收到一张环境变量表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串,最后一个字符指针为空

getenv()是获取指定的一个环境变量

main函数的第三个参数接收的实际上就是环境变量表
用命令行第三个参数 env[ ] ,可以获取全部的环境变量

     #include<stdio.h>
     #include<stdlib.h>
     #include<string.h>
  int main(int argc , char * argv[] , char * env[]) 
     {
       int i=0 ;
      for( ; env[i] ; i++ )
      {
        printf("[%d]  %s\n", i , env[i]);                                                               
     }
     return 0; 
     }

在这里插入图片描述

用c语言提供的environ函数获取环境变量 ,让environ指针指向父进程所对应的环境变量表数据
在这里插入图片描述
在这里插入图片描述

set:显示本地定义的shell变量和环境变量

[cxq@iZ7xviiy0goapxtblgih6oZ lesson12]$ set

本地变量是不会被子进程继承的 ,只会在bash内部有效

Linux中有两种命令
1、常规命令:
通过创建子进程完成的
2、内建命令:
bash不创建子进程,而由自己亲自执行,类似于bash调用了自己写的,或者系统提供的函数 , 例如echo ,cd

如果你觉得这篇文章对你有帮助,不妨动动手指给点赞收藏加转发,给鄃鳕一个大大的关注
你们的每一次支持都将转化为我前进的动力!!

  • 38
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鄃鳕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值