01-《UNIX高级环境编程》全书精华集锦(更新中)

众所周知,Linux系列知识极其重要,公司面试、实际开发都需要用到。最近看了一些资料之后,发觉自己很多地方没有掌握到位,于是开始逐一查阅,顺便整理了这个懒人版供大家参考。

1 引子

每个需要详细了解问题下面👇需要的信息都给出了相应的参考链接,有些还配上了实际操作,相信你认真看完本文之后对于UNIX操作系统基础能有一个更加清晰的认识。

2 正文

(1)什么是操作系统?

什么是UNIX操作系统?什么是Linux操作系统?它们之间的关系是怎样的?

  • 操作系统:控制计算机硬件和软件资源,对作业进行合理的调度,以供用户方便使用的一组软件的集合。
  • UNIX操作系统,是一个强大的多用户、多任务操作系统,支持多种处理器架构,按照操作系统的分类,属于分时操作系统。
  • Linux,即GNU/Linux,是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。
  • Linux继承了Unix以网络为核心的设计思想,它能运行主要的UNIX工具软件、应用程序和网络协议。

##(2)UNIX操作系统有哪些典型的分支?

Linux,Mac OS X,BSD系列与Solaris

##(3)什么是Shell?内置变量$$、$*、$@、$?、$#的具体含义是什么?

shell是一个命令语言解释器,是用户和UNIX内核直接的接口,它拥有自己内建的shell命令集,shell也能被系统中其他应用程序所调用。用户在提示符下输入的命令都由shell先解释然后传给UNIX核心。

  • $$ 是shell脚本运行的当前进程ID号
  • $* 是以一个单字符串显示所有向shell脚本传递的参数
  • $@ 是传递给shell脚本的所有参数列表
  • $? 显示最后命令的退出状态,0表示没有错误,其他表示有错误
  • $# 是传给脚本的参数个数

##(4)常用的Shell命令,如ls、cd、dd、pwd、ps、cp、chown、chmod、mkdir等的具体用法。

  • ls 列出目录下的文件
  • cd 改变当前目录
  • dd 用指定大小的块拷贝一个文件,并在拷贝的同时进行指定的转换(cc已被用来代表CComplier)
  • pwd 查看当前工作目录
  • ps显示系统中当前运行的进程状态
  • cp 复制文件
  • chown 更换所有者
  • mkdir 创建一个目录
  • chmod 改变文件访问权限

##(5)什么是内部命令?什么是外部命令?它们的区别是什么?

内部命令在系统启动时就调入内存,是常驻内存的,所以执行效率高。
外部命令是系统的软件功能,用户需要时才从硬盘中读入内存。

  • 内部命令:内部命令被构建在shell之中。当执行shell命令时,内部命令的执行速度非常快。这是因为没有其他的进程因为执行这条命令而被创建。比如说,当我们执行“cd”命令时,没有进程被创建。在执行过程中只是简单的改变当前的目录。

  • 外部命令:外部命令并没有被构建在shell中。这些可执行的外部命令保存在一个独立的文件当中。当一个外部命令被执行时,一个新的进程即被创建同时命令被执行。比如说,当我们执行“cat”(通常被保存在/usr/bin目录下)命令时,然后/usr/bin/cat被执行。

##(6)什么是C语言的头文件?有哪些是操作系统提供的头文件?哪些是C语言的标准头文件?

头文件作为一种包含功能函数、数据接口声明的载体文件,主要用于保存程序的声明。
C语言的标准头文件:ISOC标准定义的头文件
操作系统提供的头文件:POSIX标准定义的头文件

##(7)C语言程序的基本结构是怎样的?编译器怎样搜索头文件?

  • 顺序结构,选择结构,循环结构
  1. C语言,使用include指令,包含头文件,但又细分两种形式:
    1、形式一:#include “file1”
      gcc先在当前目录(指包含本条#include指令的源文件所在的目录)寻找file1,如果找不到,继续在由-iquote选项(如果有的话)指定的目录中寻找file1。
       例如,在文件/usr/include/sys/stat.h中,包含指令#include “types.h”,那么gcc先在/usr/include/sys目录下寻找types.h文件。嗯,在该目录下,确实存在一个types.h的文 件。现假设我们把这个文件移动到另一个目录:mv /usr/include/sys/types.h /bar/foo/,我们在编译时,可以通过-iquote选项,在不改变stat.h的情况下,正常编译(当然,通常不建议这样做):
    gcc -iquote /bar/foo -I/usr/include/sys *.o
    2、形式二:#include
      gcc按照以下顺序查找file2:
    -Idir1 -Idir2 …
    /usr/local/include
    libdir/gcc///include
    /usr//include
    /usr/include
    第 一行中,-Idir1 -Idir2 … 是用户通过gcc的-I选项指定的目录。值得一提的是,放在/usr/local/include/下的头文件也会被gcc自动的检索,这与/usr /local/lib/目录下的库处理方式是不一样的。

##(8)怎样利用gcc编译源文件?gcc的-o、-e、-static、-Wall等选项的具体含义是什么?怎样使用?

-o 制定目标名称,缺省的时候,gcc 编译出来的文件是a.out
-e 使用-E 选项,执行预处理工作
-static 此选项将禁止使用动态库,所以,编译出来的东西,一般都很大,也不需要什么动态连接库,就可以运行
-Wall 生成所有警告信息

##(9)什么是动态链接库?什么是静态链接库?怎样用静态链接的方式编译C程序?

静态库是在链接阶段被链接的,所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行。
有别于静态库,动态库的链接是在程序执行的时候被链接的。所以,即使程序编译完,库仍须保留在系统上,以供程序运行时调用。
gcc -static

##(10)什么是文件系统?UNIX的文件系统有什么特点?有哪些具体的文件类型?

文件系统是操作系统用于明确存储设备(常见的是磁盘,也有基于NAND Flash的固态硬盘)或分区上的文件的方法和数据结构;即在存储设备上组织文件的方法。
Unix可以把一个能随机存取的存储介质(如:硬盘、软盘和光盘)上的存储空间划分成一致多个区域,每个区域都可以像独立的物理设备一样单独进行管理和数 据存取,这样的存储区域,即是逻辑设备。在逻辑设备上按照一定的格式进行划分,就构成了逻辑文件系统,简称文件系统。

  1. 普通文件 这种文件包含了某种形式的数据,这些数据无论是文件还是二进制对于 UNIX 内核而言都是一样的。对普通文件内容的解释有处理该文件的应用程序进行。
  2. 目录文件 目录文件包含了其他文件的名字以及指向与这些文件有关信息的指针。对一个目录文件具有读权限的任一进程都可以读取该目录的内容,但是只有内核才能直接写目录文件。
  3. 块特殊文件 这种文件类型提供对设备带缓冲的访问,每次访问以固定长度为单位进行。
  4. 字符特殊文件 这种文件类型提供对设备不带缓冲的访问,每次访问长度可变。系统中的所有设备要么是字符特殊文件,要么是块特殊文件。
  5. FIFO 这种类型文件用于进程间通信。也称为命名管道(namedpipe)。
  6. 套接字(socket) 这种文件类型用于进程间的网络通信。
  7. 符号链接(symbolic link) 这种文件类型指向另一个文件。

##(11)什么是文件的访问权限?使用chmod命令怎样改变访问权限?chmod 0777是什么意思?

在linux中的每一个文件或目录都包含有访问权限,这些访问权限决定了谁能访问和如何访问这些文件和目录
chmod [mode] 文件名(其中mode可用二进制数表示)
u :目录或者文件的当前的用户
g :目录或者文件的当前的群组
o :除了目录或者文件的当前用户或群组之外的用户或者群组
(u) (g) (o)


— = 0
rwx = 7
0777–>-rwx rwx rwx
对所有用户开放所有权限

##(12)怎样解读ls -l 命令显示的文件信息?

ls -al.png

$ ls -l sobsrc. tgz
-rw-r--r-- 1 root root 483997 Ju1 l5 17:3l sobsrc. tgz

r代表只读,w代表写,x代表可执行,-代表空许可。
注意这里共有10个位置。第一个字符指定了文件类型。在通常意义上,一个目录也是一个文件。如果第一个字符是横线,表示是一个非目录的文件。如果是d,表示是一个目录。
table.png

##(13)什么是管道?什么是文件重定向?dup()、dup2()函数怎样使用?

int dup (int filedes);
int dup2 (int filedes, int filedes2);
  • 两函数的返回值:若成功则返回新的文件描述符,若出错则返回-1
    由dup返回的新的文件描述符一定是当前可用文件描述符中的最小数值。用dup2则可以用filedes2参数指定新的描述符的数值。如果filedes2已经打开,则先将其关闭。若filedes等于filedes2,则dup2返回filedes,而不关闭它。

##(14)什么是文件的静态属性和动态属性(文件描述符属性)?在文件描述符属性中,哪些是由进程维护的?哪些是由内核维护的?

图解

理解具体情况,需要了解由内核维护的3个数据结构:

  • 进程级文件描述符表(file descriptor table)
  • 系统级打开文件表(open file table)
  • 文件系统i-node表(i-node table)

这3个数据结构之间的关系如下图所示:
inode.png

内核使用三种数据结构表示打开的文件,分别是文件描述符表、文件表和 V 节点表。

(1) 每个进程在进程表中都有一个记录项,记录项中包含有一张打开文件描述符表,每个描述符占用一项。与每个文件描述符相关联的是:
(a) 文件描述符标志。
(b) 指向一个文件表项的指针。

(2) 内核为所有打开文件维持一张文件表。每个文件表项包含:
(a) 文件状态标志(读、写、添写、同步和非阻塞等)。
(b) 当前文件偏移量。
(c) 指向该文件 V 节点表项的指针。

(3) 每个打开文件(或设备)都有一个 v 节点(v-node)结构。v 节点包含了文件类型和对此文件进行各种操作的函数的指针。v 节点还包含了从磁盘读取的 i 节点(i-node)的信息,i 节点信息包含了文件的所有者、文件长度、文件所在的设备、指向文件的实际数据块在磁盘上的所在位置的指针等。

##(15)什么是会话(Session)、进程组?它们之间有什么关系?

(1) 会话是一个或多个进程组的集合。

(2) 进程组是一个或多个进程的集合,通常它们与一组作业相关联,可以接受来自同一终端的各种信号。每个进程组都有唯一的进程组ID(整数,也可以存放在pid_t类型中)。

每个进程组都有一个组长进程,组长进程的标识是进程组ID等于其进程ID。进程调用setsid函数创建一个新的会话,该进程会变成新会话的会话首进程,该进程也成为一个新进程组的组长进程。如果此调用进程已经是一个进程组的组长,则此函数返回出错。

(3)
一个会话可以包含多个进程组,一个会话对应一个控制终端。

 [示例图](http://blog.csdn.net/yh1548503342/article/details/41891047)

##(16)父进程和子进程之间是什么关系?怎样在父子进程之间共享文件描述符?

(1)由fork创建的新进程被称为子进程(child process)。

该函数被调用一次,但返回两次。两次返回的区别是子进程的返回值是0,而父进程的返回值则是新进程(子进程)的进程 id。将子进程id返回给父进程的理由是:因为一个进程的子进程可以多于一个,没有一个函数使一个进程可以获得其所有子进程的进程id。对子进程来说,之所以fork返回0给它,是因为它随时可以调用getpid()来获取自己的pid;也可以调用getppid()来获取父进程的id。(进程id 0总是由交换进程使用,所以一个子进程的进程id不可能为0 )。

fork之后,操作系统会复制一个与父进程完全相同的子进程,虽说是父子关系,但是在操作系统看来,他们更像兄弟关系,这2个进程共享代码空间,但是数据空间是互相独立的,子进程数据空间中的内容是父进程的完整拷贝,指令指针也完全相同,子进程拥有父进程当前运行到的位置(两进程的程序计数器pc值相同,也就是说,子进程是从fork返回处开始执行的),但有一点不同,如果fork成功,子进程中fork的返回值是0,父进程中fork的返回值是子进程的进程号,如果fork不成功,父进程会返回错误。可以这样想象,2个进程一直同时运行,而且步调一致,在fork之后,他们分别作不同的工作,也就是分岔了。

(2)父子进程共享文件描述符的条件:在fork之前打开文件。

未完待续

3.

本博客将长期更新维护。

个人主页