Linux复习——总结篇

本篇涵盖课程《Linux程序设计》考点,分为三部分,如下:

第一部分:Linux历史、基础知识、shell、Linux编程等内容
第二部分:部分常见的系统调用和I/O库函数
第三部分:部分编程复习题,包括了shell编程和c编程



第一部分——复习总纲

一、基础

1.Linux是谁开发的、是用什么语言开发的、Unix的开源精神——这些

  1991年Linus Torvalds(林纳斯.托瓦兹)写出Linux内核的第一个版本;
  1992年第一个发行版出现;
  GNU/Linux系统=Linux内核+GNU;发行版有:Red Hat,Debain,Suse,Mandrake,Redflag...
  GNU:即革奴计划,由理查德.斯托曼发起,目标是创建一套完全自由的操作系统;
  其他:EMACS、Copyleft

2.分区的基本知识(今年不考?)

了解的话直接看笔记就ok;

3.文件系统

 操作系统中负责存取和管理文件的部分;
 文件和文件的某些元素的集合,它为链接到文件的文件序列号提供了一个命名空间;
  1)Linux文件系统类型:VFS / EXT2,EXT3,FAT32
  VFS:virtual file system,虚拟文件系统。一个位于异构文件系统之上的软件粘合层,为访问文件系统的系统调用提供一个统一的抽象接口;它的作用就是采用标准的Unix调用读写位于不同物理介质上的不同文件系统。
  2)Linux文件夹结构(常用结构要知道,如boot,root,home,dev这些)
  在Linux中,所有的文件和目录都被组织成一个根节点开始的倒置的树状结构;
  /bin:binary,存放最常使用的命令;
  /boot:启动Linux时使用的一些核心文件,包括一些连接文件和镜像文件;
  /dev:device,存放Linux的外部设备;在Linux中,访问设备和访问文件的方式是相同的;
  /etc:存放所有的系统管理所需要的配置文件和子目录;
  /home:用户的主目录
  /lib:存放着系统最基本的动态连接共享库;
  /media:Linux系统会自动识别一些设备,如U盘、光驱等,识别后,Linux会把被识别的设备挂载到这个目录下;
  /mnt:为了让用户临时挂载别的文件系统用,如可以将光驱挂载在/mnt上,然后进入该目录就可以查看光驱里的内容了;
  /root:系统管理员的用户主目录;
  /tmp:存放一些临时文件
  /usr:用户的很多应用程序和文件
  /var:存放在不断扩充着的东西,习惯性将那些经常被修改的文件放到这个目录下, 包括各种日志文件;
3)启动过程(理解即可,不用考)
  BIOS--MBR--Boot loader--Init process
  BIOS检查设备、加载并启动MBR----MBR中的bootloader(常见有LILO和GRUB两种)加载和启动Linux内核--现在控制权就交给内核了。

4.安装软件的方式(简单看一下,apt-get要知道,其他不用)

apt-get command
*:apt-get是Debian、Ubuntu发行版的包管理工具,与Redhat中yum工具类似;一般需要root权限:
  apt-cache search string:在软件包列表中搜索字符串
  apt-get install packagename:安装一个新的软件包
  apt-get update; apt-get remove packagename; apt-get remove --purge packagename; apt-get autoremove packagename; apt-get autoclean;.....
   apt属于Debian系,rpm属于Redhat系;

5.命令:常用的命令

  passwd:改变密码; 
  mkpasswd:生成随机密码; 
  date:显示当前日期和时间;
  cal:显示日历;
  who/finger:显示当前系统的active用户(finger需要另外安装,如在Ubuntu中sudo apt install finger)
  clear:清空屏幕;
  echo:直接输出echo后面的文本;
  write:向指定登录用户终端发送消息;
  wall:向系统当前所有打开的终端发送消息;
  talk:和指定用户聊天;
  msg:用于设置其他用户是否可以直接向当前用户终端发送消息,msg y表示允许,msg n表示禁止;

6.文件类型——七种

1)常规文件:文本或code数据,没有特殊的内部结构;
2)字符特殊文件:见33)块特殊文件:特殊文件代表硬件或逻辑设备,通常在/dev中;字符特殊文件通常是装置文件中的串行端口设备,如键盘、鼠标等一次性读取设备;块特殊文件表示装置文件中的可供存储的接口设备(可随机存取装置);
4socket,即套接口文件/数据接口文件:socket,又名“套接口”,用于描述IP地址和端口,应用程序是通过套接字向网络发送请求或者应答网络请求;例如启动mysql服务器时会产生一个mysql.sock文件;
5)符号链接文件:symbolic link,类似Windows中的快捷方式
6)目录:内容的表;目录内文件的列表;
7)管道文件:fifo

7.基本命令——文件系统相关(过一遍)

1)目录
  pwd:显示当前目录
  cd:切换目录
  mkdir:创建目录;options:-m<权限>,创建目录时同时设置权限;-p:一并建立上层目录(如果不存在);
  rmdir:删除目录(最好是空目录,否则用-r递归删除其下的子目录和文件——但是这样做有危险;即先用rm删除目标目录下的文件,再用rmdir删除这个目录)
  ls:以列表形式显示目录内容,有-l,-a,-R等选项——这个命令很重要,参考8
2)文件
  touch:更新文件权限或最后修改时间(创建文件同样使用这个命令,格式为:touch filename)
  cp:复制文件;cp [options] 源文件 目标文件;options:-r/R递归、-l对源文件建立硬链接而非复制文件;-s建立符号链接;
  mv:移动和重命名文件/目录; mv source target
  ln:链接文件;默认创建硬链接,使用-s选项创建符号链接(软链接);------参照8
  rm:删除文件
  cat:输出文件内容
  more/less:逐页显示文件;more以全屏幕的方式按页显示文本文件的内容;less与more类似,不同的是more只能往前(即往下)翻页,而less既允许用户向前,也允许向后浏览文件;

7.硬链接和符号链接:

1)为文件创建硬链接:ln,但不能为目录创建硬链接;创建硬链接后,文件的Inode会被多个文件项公用。文件的硬链接数可以在ls -l后的列表的第二列看到,无额外链接的文件的连接数为1
    硬链接可以理解为多个文件指向同一个物理地址,所以不能对目录做硬链接,也不可以在不同的文件系统之间做硬链接;

2)软链接/符号链接:ln -s,将一个路径名链接到一个文件。这些创建出来的软链接文件是一种特别类型的文件,实际上它只是一个文本文件,其中包含了链接时的源文件的路径名,而源文件才是实际包含所有数据的文件;软链接产生的这个文件在ls -l中第一列会显示一个l,即表示符号链接文件(而硬链接的第一列依然是-,即文件);
  软链接可以理解为快捷方式(也就是通过它飞快地找到源文件,而不是直接去找物理地址),它本身确实是一个新的文件,它的大小就是符号链接中路径的字节数;所以它具有和源文件不同的inode号,而硬链接并没有建立新文件;此外,软链接可以对目录进行,也可以在不同的文件系统之间做符号链接;
注:如果递归地做软链接,ln -s产生的文件会全部指向源文件(即真正的文件);而cp -s复制产生的符号链接文件只会指向上一个文件(可能是符号链接,也可能就是文件,具体要看源文件的类型)
  软链接时推荐源文件使用绝对路径,如果使用相对路径,则软链接文件(即目标文件)必须与源文件在同一级目录下;

8.文件属性(ls -l,很重要哒)

ls -l: 文件类型 权限 硬链接数目 所有者 用户组 文件大小 修改时间 文件

Example:

-rw-------. 3 zfh zfh 2722 116 19:26 nohup.html
-rwxrw-r--. 1 zfh zfh 672 116 18:43 OnlineExam项目说明文档.html
lrwxrwxrwx. 1 zfh zfh 7 48 21:39 s.sql -> ./b.sql
-rw-rw-r--. 1 zfh zfh 25 48 11:51 test.sh
-rw-------. 3 zfh zfh 2722 116 19:26 x2.html

如上,解释如下:

1)第一列,第一个符号表示文件类型,-表示文件,d表示目录,l表示符号链接文件,b表示块特殊文件,c表示字符特殊文件,其他的还有socket文件(s)和管道文件(p)——具体参照7;
   后面的九个字符依次表示文件所有者、所有者所在用户组、其他用户对这个文件的权限,rwx分别表示readwrite,execute,如果是-则表示没有这项权限;
2)第二列,硬链接的数量,如果没有硬链接,默认是1
3)第三列,文件所有者
4)第四列,文件所有者所在的用户组
5)第五列,文件大小,单位是字节,如果是特殊文件(即设备),那么这一列指主设备号(第六列就会是次设备号),如果是目录,那么指目录大小(目录内的inode列表所占空间,而不是里面所有文件的总和大小)
6)第六列,文件的创建日期或最近修改日期(centos中依次是月、日、时间,Ubuntu中依次是)
7)第七列,文件名

9.文件属性修改(chmod, chown, chgrp)

对于8中的文件属性,如权限、用户、用户组,依次使用chmod, chown, chgrp命令修改;

1)更改文件权限:chmod,两种方式——数字或符号;
  对于符号,chmod u/g/o/a  +/-/=  r/w/x 文件或目录;其中u表示user,g表示group,o表示others,a表示all;(注意:用户、操作符、权限必须要连起来写)
  对于数字,chmod [-R] xyz 文件或目录,-R表示递归,xyz分别由三组权限属性值对应的数字累加而成,其中r=4,w=2,x=1,如chmod 761 f.txt,就表示f.txt的权限被改成了rwx rw- --x  

2)更改文件所有者或组:chown [-R] user:[group]  filename

3)更改文件所在组:chgrp [-R] group filename;
chown和chgrp需要在root权限下执行;且上面的user和group既可以是名字也可以是ID

10.umask命令与默认权限

  umask命令用来设置限制新建文件权限的掩码。当新文件创建时,其最初的权限由默认权限与umask掩码共同决定。文件的默认权限是666,即rw-rw-rw-,目录的默认权限是777,即rwxrwxrwx。而在此基础之上,umask设置的掩码将会从以上权限中把相应位置的权限拿走(即删去指定位的权限)
  如umask设置的掩码为022,那么新文件的权限上用户组和其他用户的write权限就会被拿走,也就是文件权限变成了644,即rw-r-r-,而新建文件夹的权限也变成了rwxr-xr-x,即755.
  再umask设置的掩码为245,即分别拿走属主、用户组、其他用户的写、读、读和执行权限,也就是说新建文件权限变成r---w--w-,即422,而文件夹的权限变成了r-x-wx--w-,即532.
  综上,umask掩码的作用即是“拿走”相应位置上的权限(如果有的话——总之,这个位置没有权限了。)
  umask语法:
    umask,显示当前权限掩码,如0245umask -S,以符号方式显示当前权限掩码,如u=rx,g=wx,o=w
(数字表示的是删掉的权限,符号表示的是剩下的权限)

11.进程概念(进程的信息不考、开始和结束进程不考)

  进程是一个任务,是一个正在执行的程序实例。它由执行程序、它的当前值、状态信息以及通过操作系统管理此进程执行情况的资源组成;
  从更小的角度看,进程是由一个地址空间和在这个地址空间内执行的一个或多个线程,以及这些线程所需要的系统资源组成;
  所有的进程都是由其他进程启动的(除了init,它是由Linux内核启动的),这是一个树层次结构,可以用pstree查看;

12.内核和外围程序构成(要理解)

shell是用户和操作系统的接口;

二、命令

1.重定向和管道(重点;还有,用shell怎么实现重定向?;管道要理解)

1)重定向:Linux重定向是指修改原来默认的一些东西,对原来系统命令的默认执行方式进行改变,比如说将原本会在显示器上显示的输出输出到某一文件中。
  I/O重定向通常与FD(File Descriptor)有关,shell的FD通常为10个,即0-9,常用的有三个,0stdin,标准输入)、1stdout,标准输出)、2stderr,标准错误输出),默认与keyborad、monitor有关;
  用<来改变读进的数据信道(stdin),使之从指定的档案读进;用>来改变送出的数据信道(stdout,stderr),使之输出到指定的档案;
  0是<的默认值,因此<与0<是一样的;同理,>与1>是一样的;
  在IO重定向中,stdoutstderr的管道会先准备好,才会从stdin读进资料;
 基本IO:
    cmd > filestdout重定向到file文件中;
    cmd > > filestdout重定向到file文件中(追加);
    cmd 1> filestdout重定向到file文件中;
    cmd > file 2>&1stdoutstderr一起重定向到file文件中;
    cmd 2> filestderr重定向到file文件中;
    cmd 2>> filestderr重定向到file文件中(追加);
    cmd >> file 2>&1stdoutstderr一起重定向到file文件中(追加);
    cmd < file >file2:cmd命令以file文件作为stdin,以file2文件作为stdout;
    cat <> file 以读写的方式打开file;
    cmd < file:命令以file文件作为stdin;
    cmd << delimiter Here document,从stdin中读入,直到遇到delimiter分界符;
2)管道:  管道"|"(pipe line):上一个命令的stdout接到下一个命令的stdin;
  一个进程的输出作为另一个进程的输入;
  例如:ls | wc -l ;  ls | grep 'txt'; 

2.PATH环境变量:echo/env/set要知道

1)概念:环境变量是在操作系统中一个具有特定名字的对象,它 包含了一个或者多个应用程序所将使用到的信息。环境变量相对于给系统或用户应用程序设置的一些变量。比如在Windows或DOS操作系统中的path变量,当要求系统运行一个程序而没有告诉它程序所在的完整路径时,系统除了在当前目录下面寻找此程序外,还应到path中指定的路径去找;
2)命令——查看和设置环境变量:
  echo:使用echo查看单个环境变量,如:echo $PATH,输出:
/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin
  env:使用env查看所有环境变量
  set:使用set查看所有本地定义的环境变量(看起来像是一个个函数)
  shell中:在shell中使用【export 变量名=$环境变量名】,可以自定义shell变量,它的值就是环境变量的值。该变量只在当前的shell或其子shell中有效,shell关闭了,变量也就失效了,例如:
code:
#!/bin/bash
pa=$PATH
echo "path=$pa"

execute,输出:path=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin

3.三个神器——find、sed、grep(基本概念知道就行,sed后面是正则表达式,大概是干嘛的,grep是干嘛的)、正则表达式不考

1)find:用来在指定目录下查找文件,参数是查找文件的起始目录,根据文件或正则表达式进行匹配;
具体参照:https://man.linuxde.net/find
2)sed:流编辑器,处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区的内容,然后输出到屏幕,接着处理下一行,直到文件末尾;文件的内容并未改变,除非使用重定向存储输出;sed主要用于自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等;
具体参照:https://man.linuxde.net/sed
3)grep:global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来,是一种强大的文本搜索工具,它能使用正则表达式搜索文件,并把匹配的行打印出来;
常见用法:在文件中搜索一个单词,命令会返回一个包含“match_pattern”的文本行:
grep match_pattern file_name / grep “match_pattern” file_name
也可以使用管道,cat file_name | grep “match_pattern”,cat的参数也可以是一串字符串,这样后面的grep就是在这个字符串中寻找匹配;
参照:http://man.linuxde.net/grep


三、shell编程(一定要掌握,有编程题)

A command interpreter and programming environment.
shell是用户与操作系统之间的接口;

1.shell不同的类型(了解)

2.执行脚本的方法:三种,要看!

如脚本x.sh
1)作为可执行程序:
  chmod +x ./x.sh  使脚本具有可执行权限
  ./x.sh  执行脚本
2)作为解释器参数
  sh x.sh 或 /bin/sh x.sh
  注:这种方式不需要在脚本第一行指定解释器参数,即#!/bin/bash
3)source x.sh 或 . x.sh

3.用户变量、环境变量(不单独考,可能有path和home):参数变量和内部变量要知道

 用户变量:shell中自定义的变量
 环境变量:操作系统变量,为OS或应用程序服务,如$PATH;shell也可以自定义;
 参数变量:运行shell时传入的参数,以及额外产生的一些变量
 内部变量:shell中的用户变量只能在当前shell中使用,即内部变量,而不能被shell运行的其他命令或shell程序使用,此时使用export命令可以将局部变量/内部变量编程全局变量(也可以称为环境变量,在shell运行结束后失效);
  三种定义全局变量/环境变量的方式:
    1)export name=value
    2)name=value;export name
    3)declare -x name=value

4.read shell不会考怎么用、引号的用法要清楚

1)shell中的引号:
  单引号:单引号中的任何字符都会原样输出,转义失败,变量也是无效的;
  双引号:里面可以有变量,也可以出现转义字符(即$ `` \将分别被bash解释)
2)shell用户变量:
  字符串:${#name}得到长度;${name:2:3}从第三个字符开始提取三个字符;`expr index "${name}"  objectStr`在name中查找objectStr子字符串;x\
  数组:
#!/bin/bash
array=(v0 v1 v2 "v3")
array[1000]="m_number"

#print all elements
echo ${array[@]}
echo ${array[*]}

#print array length
echo ${#array[@]}
echo ${#array[*]}

#print a element
echo ${array[1000]}

#print length of a element
echo ${#array[2]}	输出: [zfh@localhost ss]$ ./x.sh
v0 v1 v2 v3 m_number
v0 v1 v2 v3 m_number
5
5
m_number
2

3)运算符:
  算术运算 `expr $a + $b ` (+、-、\* 、/ 、%)
  条件表达式:用方括号[]包含在内,两端需要留空格;如
    [ $a == $b ]
    关系运算:[ $a -gt $b ] (-eq -gt -ne -lg -ge -le)
    布尔运算:[ !false ]、[ true -o false]、 [true -a true]
    逻辑运算:[[ true && false ]]、 [ true || false ]
    字符串运算:[ $a = $b ](!= -z  -n),还有[ $a ]检测字符串a是否为空
    文件测试运算:[ -b $file ]是否为块设备文件(-c, -d, -f, -p, -r , -w, -x, -s, -e)
  注:test命令可以起到和方括号类似的作用,如test $a -eq $b

4echo命令
 read命令:读取输入;
 read选项:-p表示后面的输出提示字符,不会换行;-n后面的数字表示输入的字符长度限制;-t限时,-s隐藏输入内容;

5.要看的:参数、条件、case循环、杂项命令(break、continue、exit….)、函数(好像不考,建议一看)、算术扩展和参数扩展(好好看一看)

1ifforwhile、util、case
  注意:
    let "x++"命令,是bash中用于计算的工具,使用变量不需要$
    read命令:如read FILM,读取键盘输入并命名为FILM变量

2)shell函数:稍微看了一遍
3)shell文件包含:包含外部的脚本用于封装公用的代码
 . filename #注意点号和filename之间有一个空格
 或者:source filename
4)杂项命令:
  参照:http://blog.163.com/bobile45@126/blog/static/96061992201311712658570/
  exit n:以退出码n退出脚本运行;即在exit位置退出当前shell,退出码为n,退出后可以使用$?来获得上一个命令的退出码。退出码:0表示成功,非0表示失败,2表示用法不当,127表示命令没有找到,126表示不是可执行的,>=128信号产生;
  export:定义环境变量(参照上面三种定义环境变量的方式);在一个脚本定义了环境变量后,如果在另一个脚本中运行这个脚本,那么两个脚本都可以使用这个被定义的环境变量,直至脚本运行结束;
  set:为shell设置参数变量(目前看只能set value,然后$1的值就会变成value)
  unset:从环境中删除变量或函数(如unset name,那么字符串变量name就被删除了)
  trap:trap "command" exit;退出时执行command命令
  ":":冒号,空命令
  ".":点号或source:在当前shell中执行命令——如执行其他脚本,比如在x.sh中写source test.sh,就会在执行到这一行的时候去执行test.sh脚本;

5)捕获命令输出:即执行命令,然后通过shell去获得命令执行的结果
  $(command) 或 `command`
  如:echo $(ls) 或 echo `ls`

6)算术扩展——即shell算术运算和条件判断的另一种写法
  $((...))
  如:x=$(($x+1)),等价于高级语言里的x++
  又如:(( $x>= 2 )),等价于[ $x -ge 2 ]
  注意:双层括号与方括号不一样之处在于中间不需要空格来分割;此外,下面这个示例也可以用`expr ...`的形式;

7)参数扩展——即针对参数进行一些操作
参数扩展    描述
${param:-default}  如果param为空,就设置它为default的值
${#param}  给出param的长度
${param%word}  从param的尾部开始删除与word匹配的最小部分,然后返回剩余部分
${param%%word} 从param的尾部开始删除与word匹配的最长部分,然后返回剩余部分
${param#word}  从param的头部开始删除与word匹配的最小部分,然后返回剩余部分
${param##word} 从param的头部开始删除与word匹配的最长部分,然后返回剩余部分

8)即时文档——输入输出重定向的一种,理解为将shell中的变量作为命令的输入;
  command << delimiter
    document
  delimiter
  例如: 
 #!/bin/bash
cat >> file.txt << !fs!
  Hello, this is a here document.
!fs!
 它将中间的文本作为cat命令的输入,然后将cat命令的输出重定向到了file.txt中;

总结一下,概括来说呢,可以把Linux的命令都看成是shell的内容(因为它们都可以在shell里面使用),然后通过输入输出重定向、函数、流程控制等等使得shell变成了一个编程语言;


四、程序部分

1.编程题——记得要看作业

2.文件系统的编程——先了解文件系统,再看这里的编程

3.基本概念了解:c库在用户态

4.gcc gdb(gdb不考)

5.编译链接的过程(看一下,具体的过程不会考)

其他:
预处理;
为什么要链接?
静态库与动态库、静态链接方式与动态链接方式

6.gcc的参数(看一下)、扩展名不看

1) gcc -c 编译
  gcc 链接 或 编译+链接
  g++ (C++对应的命令,其实是换了前端)
2)gcc [options] [filename]
  -E:预处理
  -S:预处理+编译
  -c:预处理+编译+汇编(不链接)
  -o output_file:指定输出文件名
  -g:调用调试工具必须的符号信息
  -O/On:在程序编译、链接过程中进行优化处理
  -Wall:显示所有的警告信息
  -Idir:指定额外的头文件搜索路径(这里是i的大写)
  -Ldir:指定额外的库文件搜索路径(这里是L的大写)
  -lname:链接时搜索指定的库文件(这里是L的小写)
  -DMACRO[=DEFN]:定义MACRO
补充:
  创建静态库(.a):g++ -c StaticMath.cpp,生成目标文件StaticMath.o,然后ar打包ar -crv libstaticmath.a StaticMath.o,这样就生成了静态库libstaticmath.a
  创建动态库((.so):g++ -fPIC -c DynamicMath.cpp生成目标文件,然后g++ -shared -o libdynmath.so,这样就生成了动态库libdynmath.so,注意Linux动态库是libxxx.so形式;

7.Makefile(原理,给一个Makefile要能看得懂)

1)makefile描述模块间的依赖关系,定义了整个工程的编译规则,实现了自动化编译(make命令执行Makefile脚本)
 make命令根据makefile对程序进行管理和维护;make判断被维护文件的时序关系;
 参照:https://blog.csdn.net/haoel/article/details/2886/
2)makefile语法:
 target ... :  prerequisites...
command 
.....
target是目标文件,可以是Object file,也可以是可执行文件;prerequisites是生成target所需要的文件(源文件、目标文件、头文件);command是make要执行的命令,就是使用上面的prerequisites文件生成target的。
实际上就是文件之间的依赖关系,target这一个或多个目标文件依赖于prerequisites中的文件,其中生成规则在command中。说白一点就是:prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行;
举例:
hello : main.o kbd.o
    gcc -o hello main.o kbd.o
main.o : main.c defs.h
    cc -c main.c
kbd.o : kbd.c defs.h command.h
    cc -c kbd.c
clean :
    rm edit main.o kbd.o
注意:command之前是一个Tab键;

8.多目标(不考)、使用函数(不考)、软件设计原则(不考)

9.GCC编译器为啥要分前端后端?

如下图,将编译器分为前端和后端,前端的功能在于产生一个可以让后端处理的语法树,后端翻译语法树成为GCC的暂存器转换语言(RTL),这样使得前后端独立,使得后端无须考虑多种源语言和目标语言而专注于其他工作,消除了重复开发的工作量,提高了编译系统的开发效率;

五、程序部分2——文件系统

1.文件、文件系统

文件:文件是可以读写、包含类型和权限的对象;
文件系统:组织文件的方式;文件和某些属性的集合。 它为引用这些文件的文件序列号提供了一个名称空间。
文件系统的多种含义:
- 一种特定的文件格式
- 按特定格式进行了“格式化”的存储介质
- 操作系统(通常在内核中)用来管理文件系统以及对文件进行操作的机制及其实现——这是本章的主要话题;

2.文件类型–参照第一部分基础6

Linux文件结构:字节流

3.VFS:作用、功能,会在内核产生四种对象:vfs对象的具体含义

1)VFS的作用和功能:
- 为各类文件系统提供了一个统一的操作界面和应用编程接口
- 文件的统一管理与抽象都由VFS实现
- VFS将用户的文件操作转换为对应的驱动级别的操作(即统一的系统调用转换为各自驱动级别的操作)
2)VFS模型:
打开一个文件后,VFS会在内存中创建4个对象
- 超级块:用于描述当前的文件系统
- 索引节点对象(inode):用于唯一标识文件
- 文件对象:代表一个打开的文件,进程相关
- 目录项:用于描述文件的目录关系

4.硬软链接(重点)

可参照:https://www.ibm.com/developerworks/cn/linux/l-cn-hardandsymb-links/index.html,也可以参照第一章的第8小节

硬链接:不同的文件名对应同一个inode,不能跨越文件系统,对应系统调用link
软链接:存储被链接文件的文件名与路径,可跨越文件系统,对应系统调用symlink

5.系统调用和库函数的区别,如:open和fopen怎么用,区别是什么

系统调用和库函数都以C函数的形式出现;
1)系统调用:
- Linux内核的对外接口
- 用户程序与内核之间的唯一接口
- 提供最小接口
2)库函数
- 依赖于系统调用
- 提供较复杂功能
例如标准I/O库
3)基本I/O系统调用
open/create,close,read,write,lseek
dup/dup2
fcntl
ioctl
系统调用函数参照:https://blog.csdn.net/yuan892173701/article/details/8687590

6.文件描述符的类型、含义

  在Linux系统中,打开文件就会获得文件描述符,它是:一个很小的非负整数int fd
  Linux内核在打开文件时分配一个文件对象,文件描述符指向内核中的文件描述符表元素,此元素再指向文件对象;
  每个进程启动后至少分配3个文件描述符:标准输入、标准输出、标准错误,文件描述符依次为0,1,2,定义与unistd.h。
  基本步骤:open -> read/write -> [lseek] -> close

7.标准I/O库函数(PPT32-57,之后是高级系统调用,目录有关的函数)

1)文件流
  流与FILE结构:FILE* fp;预定义的指针:stdin,stdout,stderr;
  缓冲I/O:三种类型——全缓冲、行缓冲、无缓冲
2)标准I/O函数
流open/close
流read/write
  - 每次一个字符的I/O
- 读取一个字符
- 输出一个字符
  - 每次一行的I/O
- 读一行(从流——即文件)
- 输出一行至流(文件)
  - 直接I/O(二进制I/O- fread和fwrite——不懂诶
  - 格式化I/O
- scanf、fscanf、sscanf
- printf、fprintf、sprintf
流复位
  - fseek、ftell、rewind
  - fgetpos、fsetpos
流刷新
  - 刷新文件流。把流里的数据立刻写入文件
  #include <stdio.h>
  int fflush(FILE *stream);

8.文件系统编程的函数

比如用c写重定向要知道调用什么函数;fcntl大概了解、知道标志位就好;ioctl不考,和驱动相关直接调用驱动代码

9.缓存I/O的三种模式:

  • 全缓存:由库函数提供缓存,刷新时才写入
  • 行缓存:完成一行后写入
  • 无缓存

10.文件锁

锁起的作用:
- 几个进程同时操作一个文件
文件锁的分类:
- 记录锁
- 劝告锁:检查,加锁有应用程序自己控制
- 强制锁:检查,加锁由内核控制;影响open() read() write()等系统调用
- 共享锁
- 排他锁

fcntl记录锁——即fcntl来进行锁相关的操作
  - 用于记录锁的fcntl函数原型
  #include <unistd.h>
  #include <fcntl.h>
  int fcntl(int fd, int cmd, struct flock *lock)
  flock是一个struct,里面保存了锁的类型、锁开始的位移、锁的字节长度、阻塞锁的进度PID
  cmd参数:F_GETLK获得锁信息;F_SETLK设置锁信息;F_SETLKW同设置锁信息,wait方式;

11.安全性:防护等级大概知道每一级保护到什么程序、缓冲区溢出会考(读代码、找溢出)

六、内核

1.内核主要功能、一般不考编译内核的细节

操作系统是一系列程序的集合,其中最重要的部分构成了内核
单内核/微内核:
- 单内核是一个很大的进程,内部可以分为若干模块,运行时是一个独立的二进制的文件,模块间通讯通过直接调用函数实现;
- 微内核中大部分内核作为独立的进程在特权下运行,通过消息传递进行通讯;
Linux内核的能力:
- 内存管理,文件系统,进程管理,多线程支持,抢占式,多处理器支持

2.驱动

  • 许多常见驱动的源代码集中在内核源码中
  • 也有第三方开发的驱动,可以单独编译成模块.ko
  • 编译需要内核头文件的支持
    此外,所有驱动需要以内核态运行

开发驱动的注意事项:
- 不能使用c库来开发驱动程序
- 没有内存保护机制(内核态)
- 小内核栈
- 并发上的考虑(大量线程随机运行时驱动的运行情况是否正确)

模块之间的通讯:
- 模块是为了完成某种特定任务而设计的,其功能比较的单一,为了丰富系统的功能,所以模块之间常常进行通信。其之间可以共享变量,数据结构,也已调用对方提供的功能函数;
模块相关命令:
- 底层命令
- insmod //加载模块
- rmmod //卸载模块
- 高层命令
- modprobe
- modprobe -r //释放模块
- moddep //查询模块依赖的所有其他模块
- lsmod //列出已经装载的模块列表
- modinfo //显示模块信息

3.BootLoader Linux要看、初始化不要、用户态内核态的区别

用户态与内核态:
当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核运行态(简称内核态)。此时处理器处于特权级最高的0级(x86的特权级分为4级,0级最高,3级最低)。当进程处于内核态时,执行的内核代码会使用当前进程的内核栈。每个进程都有自己的内核栈。
当进程执行用户自己的代码时,处于用户态,特权级为3.

进入内核态:
- 系统调用
- 中断处理
- 异常


第二部分 系统调用与C库I/O函数

FD:file descriptor,一个很小的正整数,打开文件时获得
在unistd.h中,有STDIN_FILENO(0),STDOUT_FILENO(1),STDERR_FILENO(2);

一、系统调用

1.open/creat

#include <fcntl.h>
int open(const char *pathname, int flags)
int open(const char *pathname, int falgs, mode_t mode)
int creat(const char *pathname, mode_t mode)
(return: a new file descriptor if success; -1 if failure)

参数 "falgs"
- flags:文件权限
- O_RDONLY,O_WRONLY,O_RDWR,即只读、只写、读/写;还有O_CREAT表示如果不存在即创建文件;O_APPEND追加模式,O_TRUNC,O_EXCL
- creat函数等价于open使用O_CREAT|O_WRONLY|O_TRUNC

参数"mode"
- 用于创建新文件的时指定权限

2.close函数

  关闭一个文件描述符
  #include <unistd.h>
  int close(int fd);
  (return 0 if success, -1 if failure)

3.read/write函数

#include <unistd.h> 
ssized_t read(int fd, void *buf, size_t count)——即从fd对应的文件中读count个字节的数据到buf数组里;
(返回读到的字节数,若已到文件尾为0,若出错为1)

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count)——即从buf数组中读count个字节的数据写到fd对应的文件中;
(若成功返回已写的字节数,若出错为-1)

4.dup/dup2——复制文件描述符

  #include <unistd.h>
  int dup(int oldfd)
  int dup2(int oldfd, int newfd)
  (return: the new file descriptor if success; -1 if failure)
  作用:例如重定向,参照试卷shell重定向的实现

5.fcntl——文件控制

#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd)
int fcntl(int fd, int cmd, long arg)
int fcntl(ing fd, int cmd, struct flock *lock)——操作锁
(返回值:若成功依赖于cmd,若出错返回-1)

cmd参数:
F_DUPFD:复制文件描述符
F_GETFD/F_SETFD
F_GETFL/F_SETFL:获得/设置FD flags,即权限
F_GETOWN/F_SETOWN
F_GETLK/F_SETLK/F_SETLKW:获得/设置文件锁,W表示等待

二、标准I/O库函数——全部位于#include

1.文件流(FILE *)

FILE* fp;
缓冲IO:全缓冲、行缓冲、无缓冲

2.标准I/O库函数

都是针对流,即FILE*结构进行的操作;

1open/close
 FILE *fopen(const char *filename, const char *mode)
 int fclose(FILE *stream)
mode参数:r, w, a, r+, w+, a+分别表示读、写、追加、读和写、读写创建、读追加创建
2)read/write
每次一个字符的I/O
  int getc(File * fp)
  int fgetc(File *fp)
  int getchar(void)
  返回值时字符转换的int,EOF(end of file,用feof(char)来判断),error(ferror(char)判断)

  int putc(int c, File *fp)
  int fputc(int c,File *fp)
  int putchar(int c)
  返回char如果成功,失败返回-1

每次一行的I/O——从流中读size放到数组中,或把数组写到流中
  char *fgets(char *s, int size, FILE *stream)
  读最多size-1个字符,第size为换行(\0),或EOF

  int fputs(const char *s, FILE *stream)

直接I/O(二进制I/O)
  fread和fwrite

格式化I/O
  scanf, fscanf,sscanf
  printf, fprintf, sprintf
3)流复位
4)流刷新
  刷新文件流。把流里的数据立即写入文件
  int fflush(FILE *stream)

5)流与文件描述符的相互转换
int fileno(FILE *fp) ——确定流使用的底层文件描述符
FILE *fdopen(int fd)——根据已打开的文件描述符创建一个流

三、高级系统调用——位于#include

1.权限函数

#include <unistd.h>
int access(const char *pathname, int mode)返回0成功,-1失败
mode:R_OK,W_OK,X_OK,F_OK

2.chmod/fchmod函数——改变文件权限

#include <sys/types.h>
#include <sys/stat.h>
int chmod(const char *path, mode_t mode)
int fchmod(int fildes, mode_t mode)
(return 0 if success, -1 if failure)

3.chown/fchown/lchown函数——改变文件属主和用户组

#include <sys/types.h>
#inculde <unistd.h>
int chown(const char *path, uid_t owner, gid_t group)
int fchown(int fd, uid_owner, gid_t group)
int lchown(const char *path, uid_t owner, gid_t group)
``
4.link/unlink函数
创建文件的链接:
#include <unistd.h>
int link(const char *oldpath, const char *newpath)——对应了硬链接
删除一个名词,以及它可能引用的名称:
int unlink(const char *pathname)

5.symlink/readlink函数

创建新链接(包含了oldpath的新文件)

int symlink(const char *oldpath, const char *newpath)
读符号链接的值:
int readlink(const char *path, ch)

第三部分 编程复习题

卷2014

  1. 重定向是Linux中的重要机制。试分析其使用方法、应用实例,并简述实现机制。(15分)
  shell中使用<输入重定向,>输出重定向。
  如:ls -l > x.txt
      cat < x.txt
  实现机制:使用dup2系统调用实现重定向,如下列程序将标准输出重定向至文件:

2.Linux中文件描述符和文件指针FILE*的区别是什么?

文件描述符:在Linux系统中打开文件就会获得文件描述符,它是一个很小的正整数。每个进程在PCB(process control block)中保存着一份文件描述符表,文件描述符就是这个表的索引,每个表项都有一个指向已打开文件的指针;
文件指针FILE*:C语言中使用文件指针FILE*作为I/O的句柄。文件指针指向进程用户区的一个被称为FILE结构的数据结构.FILE结构包括一个缓冲区和一个文件描述符,而文件描述符是文件描述符表的一个索引,因此某种意义上说文件指针就是句柄的句柄。

3.使用C的库函数,编写一个函数void bindiff(char *file1,char *file2,char *fileo),将文件从file1、file2对应的路径中读取并逐字节比对,将相同的字节输出到fileo对应的文件中。(25分)

#include <stdio.h>
void bindiff(char *file1,char *file2, char * fileo);
int main()
{
    bindiff("1.txt","2.txt","3.txt");
}

void bindiff(char *file1,char *file2,char *fileo)
{
    FILE *fp1 = 0, *fp2=0, *fp0=0;
    char ch1,ch2;
    fp1 = fopen(file1, "r");
    fp2 = fopen(file2, "r");    
    fpo = fopen(fileo, "w");
    while(1)
    {
        ch1 = (char)fgetc(fp1);
        ch2 = (char)fgetc(fp2);
        if(feof(fp1) || feof(fp2))
        {
            break;
        }
        if(ch1==ch2)
        {
            fputc(ch2,fpo);
        }
    }   
    fclose(fp1);
    fclose(fp2);
    fclose(fpo);

}

注:使用C库函数fopen,fgetc,fputc,feof


卷2015

一、选择题 (5*6=30)

(1)用户与内核的接口是什么:系统调用(注意:用户与操作系统的接口是shell)
(2)删除文件夹的命令:rmdir
(3)重定向-输出文件内容:command > file
(4)切换用户的命令:su
(5)null

二、简答题(2*10=20)

1、为什么Linux引入makefile?和其他脚本的区别?使用makefile编译系统有哪些?特点?
自动化编译
2、硬链接与软链接的区别?(至少三点)用shell命令和函数如何创建?
这个参考复习内容

三、编程题(15+20+15=50)

1、看代码,是否有缓冲区溢出?如何改进?
今年应该不考
2、用系统调用实现输出给定文件夹中所有文件的名字 用空格隔开,并在文件夹及文本文件的输出后注上“(文件夹)”“(文本文件)”
这个明天看作业,应该就是ls命令
思路:
1)用一个bool数组来填充在命令行中输入的参数选项,分别接收-a,-l,-R,-i-d;同时使用getopt()函数解析输入
2)对于输入的每个文件或目录,循环执行ls()自定义函数
3)查阅相关资料,可根据st_mode & S_IFMT的结果来判断文件类型,并根据st_mode中1的位置来判断文件权限;

3、shell脚本编程,获得用户输入的100个整数,并输出其最大值,最小值,总和。

#!/bin/bash
i=0
min=10000
max=-10000
while (($i<100))
do
  read thisNum
  if(($thisNum<=$min))
  then
      min=$thisNum
  fi
  if(($thisNum>=$max))
  then
       max=$thisNum
   fi
    let i++
done

echo "maxNum:$max"
echo "minNum:$min"

猜你喜欢

转载自blog.csdn.net/qq_28379809/article/details/80071085
今日推荐