【Linux】Linux期末复习

Linux期末复习资料🐧

作者:鱼摆摆 2019-01-08 update for 2019-03-8

适用于四川师范大学计算机科学学院Linux高级程序设计课程

教师:张莹

Linux 复习纲要


一、选择题(Linux命令) 20’

  • who: 显示所有正在使用系统的用户、所用终端名、注册到系统的时间

    • -H 或 –heading:显示各栏位的标题信息列;
    • -i 或 -u 或 –idle:显示闲置时间,若该用户在前一分钟之内有进行任何动作,将标示成”.”号,如果该用户已超过24小时没有任何动作,则标示出”old”字符串;
    • -m:此参数的效果和指定”am i”字符串相同;
    • -q 或–count:只显示登入系统的帐号名称和总人数;
    • -s:此参数将忽略不予处理,仅负责解决who指令其他版本的兼容性问题;
  • echo: 输出命令,后面接输出内容,引号可加可不加

    1
    echo -e "OK! \n" # -e 开启转义
  • date: 用来显示或设定系统的日期与时间

    • -u : 显示目前的格林威治时间
  • pwd: 显示当前路径

  • ls: 显示文件、目录信息

    • -l: 除文件名称外,亦将文件型态、权限、拥有者、文件大小等资讯详细列出
      @import “ls-l.png”
    • -a: 显示所有文件及目录 (ls内定将文件名或目录名称开头为”.”的视为隐藏档,不会列出)
    • -r: 将文件以相反次序显示(原定依英文字母次序)
    • -t: 将文件依建立时间之先后次序列出
    • -A: 同 -a ,但不列出 “.” (目前目录) 及 “..” (父目录)
    • -R: 若目录下有文件,则以下之文件亦皆依序列出
  • cat: 用于连接文件并打印到标准输出设备上

    • -n 或 –number:由 1 开始对所有输出的行数编号。
    • -b 或 –number-nonblank:和 -n 相似,只不过对于空白行不编号。
    • -s 或 –squeeze-blank:当遇到有连续两行以上的空白行,就代换为一行的空白行。
    • -v 或 –show-nonprinting:使用 ^ 和 M- 符号,除了 LFD 和 TAB 之外。
    • -E 或 –show-ends : 在每行结束处显示 $。
    • -T 或 –show-tabs: 将 TAB 字符显示为 ^I。
    • -A, –show-all:等价于 -vET。
  • rm: 用于删除一个文件或者目录

    • -i 删除前逐一询问确认。
    • -f 即使原档案属性设为唯读,亦直接删除,无需逐一确认。
    • -r 将目录及以下之档案亦逐一删除。
  • cp: 用于复制文件或目录

    • -a:此选项通常在复制目录时使用,它保留链接、文件属性,并复制目录下的所有内容。其作用等于dpR参数组合。
    • -d:复制时保留链接。这里所说的链接相当于Windows系统中的快捷方式。
    • -f:覆盖已经存在的目标文件而不给出提示。
    • -i:与-f选项相反,在覆盖目标文件之前给出提示,要求用户确认是否覆盖,回答”y”时目标文件将被覆盖。
    • -p:除复制文件的内容外,还把修改时间和访问权限也复制到新文件中。
    • -r:若给出的源文件是一个目录文件,此时将复制该目录下所有的子目录和文件。
    • -l:不复制文件,只是生成链接文件。
  • touch: 用于修改文件或者目录的时间属性,包括存取时间和更改时间。若文件不存在,系统会建立一个新的文件

    • a 改变档案的读取时间记录。
    • m 改变档案的修改时间记录。
    • c 假如目的档案不存在,不会建立新的档案。与 –no-create 的效果一样。
    • f 不使用,是为了与其他 unix 系统的相容性而保留。
    • r 使用参考档的时间记录,与 –file 的效果一样。
    • d 设定时间与日期,可以使用各种不同的格式。
    • t 设定档案的时间记录,格式与 date 指令相同。
  • cd: 用于切换当前工作目录至 dirName(目录参数)

    • 跳到 /usr/bin/ :

      1
      cd /usr/bin
    • 跳到自己的 home 目录 :

      1
      cd ~
    • 跳到目前目录的上一层 :

      1
      cd ..
  • mkdir: 用于建立名称为 dirName 之子目录

    • -p 确保目录名称存在,不存在的就建一个。
  • rmdir: 删除空目录

    • -p 是当子目录被删除后使它也成为空目录的话,则顺便一并删除。
  • wc: 用于计算字数

    • -c或–bytes或–chars 只显示Bytes数。
    • -l或–lines 只显示行数。
    • -w或–words 只显示字数。
  • time: time命令的用途,在于量测特定指令执行时所需消耗的时间及系统资源等资讯

    • -o 或 –output=FILE:设定结果输出档。这个选项会将 time 的输出写入 所指定的档案中。如果档案已经存在,系统将覆写其内容。
    • -a 或 –append:配合 -o 使用,会将结果写到档案的末端,而不会覆盖掉原来的内容。
    • -f FORMAT 或 –format=FORMAT:以 FORMAT 字串设定显示方式。当这个选项没有被设定的时候,会用系统预设的格式。不过你可以用环境变数 time 来设定这个格式,如此一来就不必每次登入系统都要设定一次。
  • chmod: 改变文件操作权限

    • u 表示该文件的拥有者,g 表示与该文件的拥有者属于同一个群体(group)者,o 表示其他以外的人,a 表示这三者皆是。
    • + 表示增加权限、- 表示取消权限、= 表示唯一设定权限。
    • r 表示可读取,w 表示可写入,x 表示可执行,X 表示只有当该文件是个子目录或者该文件已经被设定过为可执行。
      其他参数说明:
    • -c : 若该文件权限确实已经更改,才显示其更改动作
    • -f : 若该文件权限无法被更改也不要显示错误讯息
    • -v : 显示权限变更的详细资料
    • -R : 对目前目录下的所有文件与子目录进行相同的权限变更(即以递回的方式逐个变更)
  • chown: 将指定文件的拥有者改为指定的用户或组

    • -c : 显示更改的部分的信息
    • -f : 忽略错误信息
    • -h :修复符号链接
    • -v : 显示详细的处理信息
    • -R : 处理指定目录以及其子目录下的所有文件
  • tar: 用于压缩(备份)文件

    • -A或–catenate 新增文件到已存在的备份文件。
    • -b<区块数目>或–blocking-factor=<区块数目> 设置每笔记录的区块数目,每个区块大小为12Bytes。
    • -B或–read-full-records 读取数据时重设区块大小。
    • -c或–create 建立新的备份文件。
    • -C<目的目录>或–directory=<目的目录> 切换到指定的目录。
    • -d或–diff或–compare 对比备份文件内和文件系统上的文件的差异。
    • -f<备份文件>或–file=<备份文件> 指定备份文件。
    • -F<Script文件>或–info-script=<Script文件> 每次更换磁带时,就执行指定的Script文件。
    • -g或–listed-incremental 处理GNU格式的大量备份。
    • -G或–incremental 处理旧的GNU格式的大量备份。
    • -h或–dereference 不建立符号连接,直接复制该连接所指向的原始文件。
    • -i或–ignore-zeros 忽略备份文件中的0 Byte区块,也就是EOF。
    • -k或–keep-old-files 解开备份文件时,不覆盖已有的文件。
    • -K<文件>或–starting-file=<文件> 从指定的文件开始还原。
    • -l或–one-file-system 复制的文件或目录存放的文件系统,必须与tar指令执行时所处的文件系统相同,否则不予复制。
    • -L<媒体容量>或-tape-length=<媒体容量> 设置存放每体的容量,单位以1024 Bytes计算。
    • -m或–modification-time 还原文件时,不变更文件的更改时间。
    • -M或–multi-volume 在建立,还原备份文件或列出其中的内容时,采用多卷册模式。
    • -N<日期格式>或–newer=<日期时间> 只将较指定日期更新的文件保存到备份文件里。
    • -o或–old-archive或–portability 将资料写入备份文件时使用V7格式。
    • -O或–stdout 把从备份文件里还原的文件输出到标准输出设备。
    • -p或–same-permissions 用原来的文件权限还原文件。
    • -P或–absolute-names 文件名使用绝对名称,不移除文件名称前的”/“号。
    • -r或–append 新增文件到已存在的备份文件的结尾部分。
    • -R或–block-number 列出每个信息在备份文件中的区块编号。
    • -s或–same-order 还原文件的顺序和备份文件内的存放顺序相同。
    • -S或–sparse 倘若一个文件内含大量的连续0字节,则将此文件存成稀疏文件。
    • -t或–list 列出备份文件的内容。
    • -T<范本文件>或–files-from=<范本文件> 指定范本文件,其内含有一个或多个范本样式,让tar解开或建立符合设置条件的文件。
    • -u或–update 仅置换较备份文件内的文件更新的文件。
    • -U或–unlink-first 解开压缩文件还原文件之前,先解除文件的连接。
    • -v或–verbose 显示指令执行过程。
    • -V<卷册名称>或–label=<卷册名称> 建立使用指定的卷册名称的备份文件。
    • -w或–interactive 遭遇问题时先询问用户。
    • -W或–verify 写入备份文件后,确认文件正确无误。
    • -x或–extract或–get 从备份文件中还原文件。
    • -X<范本文件>或–exclude-from=<范本文件> 指定范本文件,其内含有一个或多个范本样式,让ar排除符合设置条件的文件。
    • -z或–gzip或–ungzip 通过gzip指令处理备份文件。
    • -Z或–compress或–uncompress 通过compress指令处理备份文件。
      实例
    • 压缩文件 非打包

      1
      2
      3
      # touch a.c       
      # tar -zcvf test.tar.gz a.c //压缩 a.c文件为test.tar.gz
      a.c
    • 解压文件

      1
      2
      # tar -zxvf test.tar.gz 
      a.c
  • passwd: 用来更改使用者的密码

    • -d 删除密码
    • -f 强制执行
    • -k 更新只能发送在过期之后
    • -l 停止账号使用
    • -S 显示密码信息
    • -u 启用已被停止的账户
    • -x 设置密码的有效期
    • -g 修改群组密码
    • -i 过期后停止用户账号
  • uesradd: 用于建立用户帐号

    • -c<备注>  加上备注文字。备注文字会保存在passwd的备注栏位中。
    • -d<登入目录>  指定用户登入时的启始目录。
    • -D  变更预设值.
    • -e<有效期限>  指定帐号的有效期限。
    • -f<缓冲天数>  指定在密码过期后多少天即关闭该帐号。
    • -g<群组>  指定用户所属的群组。
    • -G<群组>  指定用户所属的附加群组。
    • -m  自动建立用户的登入目录。
    • -M  不要自动建立用户的登入目录。
    • -n  取消建立以用户名称为名的群组.
    • -r  建立系统帐号。
    • -s\指定用户登入后所使用的shell。
    • -u\指定用户ID。

      实例

    • 添加一般用户

      1
      # useradd tt
    • 为添加的用户指定相应的用户组

      1
      # useradd -g root tt
    • 创建一个系统用户

      1
      # useradd -r tt
    • 为新添加的用户指定home目录

      1
      # useradd -d /home/myd tt
    • 建立用户且制定ID

      1
      # useradd caojh -u 544
  • userdel: 用于删除用户帐号

    • -r  删除用户登入目录以及目录中所有文件。

      实例

    • 删除用户账号
      1
      # userdel hnlinux
  • grep: 用于查找文件里符合条件的字符串

    • -a 或 –text : 不要忽略二进制的数据。
    • -A<显示行数> 或 –after-context=<显示行数> : 除了显示符合范本样式的那一列之外,并显示该行之后的内容。
    • -b 或 –byte-offset : 在显示符合样式的那一行之前,标示出该行第一个字符的编号。
    • -B<显示行数> 或 –before-context=<显示行数> : 除了显示符合样式的那一行之外,并显示该行之前的内容。
    • -c 或 –count : 计算符合样式的列数。
    • -C<显示行数> 或 –context=<显示行数>或-<显示行数> : 除了显示符合样式的那一行之外,并显示该行之前后的内容。
    • -d <动作> 或 –directories=<动作> : 当指定要查找的是目录而非文件时,必须使用这项参数,否则grep指令将回报信息并停止动作。
    • -e<范本样式> 或 –regexp=<范本样式> : 指定字符串做为查找文件内容的样式。
    • -E 或 –extended-regexp : 将样式为延伸的普通表示法来使用。
    • -f<规则文件> 或 –file=<规则文件> : 指定规则文件,其内容含有一个或多个规则样式,让grep查找符合规则条件的文件内容,格式为每行一个规则样式。
    • -F 或 –fixed-regexp : 将样式视为固定字符串的列表。
    • -G 或 –basic-regexp : 将样式视为普通的表示法来使用。
    • -h 或 –no-filename : 在显示符合样式的那一行之前,不标示该行所属的文件名称。
    • -H 或 –with-filename : 在显示符合样式的那一行之前,表示该行所属的文件名称。
    • -i 或 –ignore-case : 忽略字符大小写的差别。
    • -l 或 –file-with-matches : 列出文件内容符合指定的样式的文件名称。
    • -L 或 –files-without-match : 列出文件内容不符合指定的样式的文件名称。
    • -n 或 –line-number : 在显示符合样式的那一行之前,标示出该行的列数编号。
    • -o 或 –only-matching : 只显示匹配PATTERN 部分。
    • -q 或 –quiet或–silent : 不显示任何信息。
    • -r 或 –recursive : 此参数的效果和指定”-d recurse”参数相同。
    • -s 或 –no-messages : 不显示错误信息。
    • -v 或 –revert-match : 显示不包含匹配文本的所有行。
    • -V 或 –version : 显示版本信息。
    • -w 或 –word-regexp : 只显示全字符合的列。
    • -x –line-regexp : 只显示全列符合的列。
    • -y : 此参数的效果和指定”-i”参数相同。

      实例

    • 1、在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行。此时,可以使用如下命令:

      1
      grep test *file
    • 2、以递归的方式查找符合条件的文件。例如,查找指定目录/etc/acpi 及其子目录(如果存在子目录的话)下所有文件中包含字符串”update”的文件,并打印出该字符串所在行的内容,使用的命令为:

      1
      grep -r update /etc/acpi
    • 3、反向查找。前面各个例子是查找并打印出符合条件的行,通过”-v”参数可以打印出不符合条件行的内容。
      查找文件名中包含 test 的文件中不包含test 的行,此时,使用的命令为:

      1
      grep -v test *test*
  • ps: 用于显示当前进程 (process) 的状态

    • -A 列出所有的行程
    • -w 显示加宽可以显示较多的资讯
    • -au 显示较详细的资讯
    • -aux 显示所有包含其他使用者的行程
    • au(x) 输出格式 :
      • USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
      • USER: 行程拥有者
      • PID: pid
      • %CPU: 占用的 CPU 使用率
      • %MEM: 占用的记忆体使用率
      • VSZ: 占用的虚拟记忆体大小
      • RSS: 占用的记忆体大小
      • TTY: 终端的次要装置号码 (minor device number of tty)
      • STAT: 该行程的状态:
      • D: 不可中断的静止 (通悸□□缜b进行 I/O 动作)
      • R: 正在执行中
      • S: 静止状态
      • T: 暂停执行
      • Z: 不存在但暂时无法消除
      • W: 没有足够的记忆体分页可分配
      • <: 高优先序的行程
      • N: 低优先序的行程
      • L: 有记忆体分页分配并锁在记忆体内 (实时系统或捱A I/O)
      • START: 行程开始时间
      • TIME: 执行的时间
      • COMMAND:所执行的指令
  • kill: 用于删除执行中的程序或工作、也可将指定的信号送至程序

    • -l <信息编号>  若不加<信息编号>选项,则-l参数会列出全部的信息名称。
    • -s <信息名称或编号>  指定要送出的信息。
    • [程序]  [程序]可以是程序的PID或是PGID,也可以是工作编号。

      实例

    • 杀死进程

      1
      # kill 12345
    • 强制杀死进程

      1
      # kill -KILL 123456
    • 发送SIGHUP信号,可以使用一下信号

      1
      # kill -HUP pid
    • 彻底杀死进程

      1
      # kill -9 123456
    • 显示信号

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      # kill -l
      1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
      6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
      11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
      16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
      21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
      26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
      31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
      38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
      43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
      48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
      53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
      58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
      63) SIGRTMAX-1 64) SIGRTMAX
    • 杀死指定用户所有进程

      1
      2
      #kill -9 $(ps -ef | grep hnlinux) //方法一 过滤出hnlinux用户进程 
      #kill -u hnlinux //方法二
  • mount: 用于挂载Linux系统外的文件

    • -V:显示程序版本
    • -h:显示辅助讯息
    • -v:显示较讯息,通常和 -f 用来除错。
    • -a:将 /etc/fstab 中定义的所有档案系统挂上。
    • -F:这个命令通常和 -a 一起使用,它会为每一个 mount 的动作产生一个行程负责执行。在系统需要挂上大量 NFS 档案系统时可以加快挂上的动作。
    • -f:通常用在除错的用途。它会使 mount 并不执行实际挂上的动作,而是模拟整个挂上的过程。通常会和 -v 一起使用。
    • -n:一般而言,mount 在挂上后会在 /etc/mtab 中写入一笔资料。但在系统中没有可写入档案系统存在的情况下可以用这个选项取消这个动作。
    • -s-r:等于 -o ro
    • -w:等于 -o rw
    • -L:将含有特定标签的硬盘分割挂上。
    • -U:将档案分割序号为 的档案系统挂下。-L 和 -U 必须在/proc/partition 这种档案存在时才有意义。
    • -t:指定档案系统的型态,通常不必指定。mount 会自动选择正确的型态。
    • -o async:打开非同步模式,所有的档案读写动作都会用非同步模式执行。
    • -o sync:在同步模式下执行。
    • -o atime、-o noatime:当 atime 打开时,系统会在每次读取档案时更新档案的『上一次调用时间』。当我们使用 flash 档案系统时可能会选项把这个选项关闭以减少写入的次数。
    • -o auto、-o noauto:打开/关闭自动挂上模式。
    • -o defaults:使用预设的选项 rw, suid, dev, exec, auto, nouser, and async.
    • -o dev、-o nodev-o exec、-o noexec允许执行档被执行。
    • -o suid、-o nosuid:
      允许执行档在 root 权限下执行。
    • -o user、-o nouser:使用者可以执行 mount/umount 的动作。
    • -o remount:将一个已经挂下的档案系统重新用不同的方式挂上。例如原先是唯读的系统,现在用可读写的模式重新挂上。
    • -o ro:用唯读模式挂上。
    • -o rw:用可读写模式挂上。
    • -o loop=:使用 loop 模式用来将一个档案当成硬盘分割挂上系统。

      实例

      1
      2
      mount -t iso9660 /dev/cdrom/mnt/cdrom
      mount -t nfs 127.0.0.1:/mnt/nfs/mnt/nfs
  • umount: 用于卸除文件系统

    • -a 卸除/etc/mtab中记录的所有文件系统。
    • -h 显示帮助。
    • -n 卸除时不要将信息存入/etc/mtab文件中。
    • -r 若无法成功卸除,则尝试以只读的方式重新挂入文件系统。
    • -t<文件系统类型> 仅卸除选项中所指定的文件系统。
    • -v 执行时显示详细的信息。
    • -V 显示版本信息。
    • [文件系统] 除了直接指定文件系统外,也可以用设备名称或挂入点来表示文件系统。

      实例

    • 下面两条命令分别通过设备名和挂载点卸载文件系统,同时输出详细信息:
      1
      2
      3
      4
      # umount -v /dev/sda1          通过设备名卸载  
      /dev/sda1 umounted
      # umount -v /mnt/mymount/ 通过挂载点卸载
      /tmp/diskboot.img umounted
  • vi: 文本编辑器
    "vi 编辑器"


二、GDB填空题 20’

gcc编译
-

  • GCC编译过程:
  • -预处理
  • -编译
  • -汇编
  • -链接
  • 基本语法格式:⚠️⚠️⚠️

    1
    2
    # gcc -c 源文件名.c
    # gcc -o 生成的可执行文件名(可任意,通常为源文件名去掉后缀)源文件名.o
  • 静态库的创建和使用:

  • 1、编写源文件libhello.h linhello.c
  • 2、生成目标文件libhello.o

    1
    gcc -c libhello.c -o libhello.o
  • 3、使用ar命令创建静态库libhello.a

    1
    2
    ar -rc libhello.a libhello.o
    file lib hello.a
  • 4、静态库的使用:
    编辑测试文件usehello.c,生成可执行文件usehello_static

    1
    gcc –o usehello_static usehello.c libhello.a
  • 动态库的创建和使用:⚠️

  • 1、编写源文件libhello.h linhello.c
  • 2、生成共享库目标文件libhello.o

    1
    gcc -fPIC -Wall -g -c libhello.c -o libhello.o
  • 3、编译共享库libhello.so.1.0

    1
    2
    gcc -g -shared -W1,-soname,libhello.so -o libhello.so.1.0 libhello.o
    file lib hello.so.1.0
  • 4、创建共享库的符号链接

    1
    ln –s libhello.so.1.0 libhello.so
  • 5、动态库的使用:
    编辑测试文件usehello.c,生成可执行文件usehello_dy

    1
    2
    gcc –g –o usehello_dy usehello.c –lhello –L ./
    LD_LIBRARY_PATH=$(pwd) ./usehello_dy

gdb调试器
-

  • gdb调试必须加上参数 -g

    1
    # gcc -g text.c -o text
  • 调试

    1
    # gdb filename

参数列表
-

命令命令缩写命令说明
listl显示多行源代码
breakb设置断点,程序运行到断点的位置会停下来
infoi描述程序的状态
runr开始运行程序
displaydisp跟踪查看某个变量,每次停下来都显示它的值
steps执行下一条语句,如果该语句为函数调用,则进入函数执行其中的第一条语句
nextn执行下一条语句,如果该语句为函数调用,不会进入函数内部执行(即不会一步步地调试函数内部语句)
printp打印内部变量值
continuec继续程序的运行,直到遇到下一个断点
set var name=v设置变量的值
startst开始执行程序,在main函数的第一条语句前面停下来
file装入需要调试的程序
killk终止正在调试的程序
watch监视变量值的变化
backtracebt产看函数调用信息(堆栈)
framef查看栈帧
quitq退出GDB环境



三、shell编程(上机测试 +-\/ function cdManager) 10’*

  • 运行 Shell 脚本有两种方法:

    • 1、作为可执行程序

      将上面的代码保存为 test.sh,并 cd 到相应目录:

      1
      2
      chmod +x ./test.sh  #使脚本具有执行权限
      ./test.sh #执行脚本

      注意,一定要写成 ./test.sh,而不是 test.sh,运行其它二进制的程序也一样,直接写 test.sh,linux 系统会去 PATH 里寻找有没有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的当前目录通常不在 PATH 里,所以写成 test.sh 是会找不到命令的,要用 ./test.sh 告诉系统说,就在当前目录找。

    • 2、作为解释器参数

      这种运行方式是,直接运行解释器,其参数就是 shell 脚本的文件名,如:

      1
      2
      /bin/sh test.sh
      /bin/php test.php

系统预定义变量

参数处理说明
$#传递到脚本的参数个数
$*以一个单字符串显示所有向脚本传递的参数。
如”$*”用「”」括起来的情况、以”$1 $2 … $n”的形式输出所有参数。
$$脚本运行的当前进程ID号
$!后台运行的最后一个进程的ID号
$@与$*相同,但是使用时加引号,并在引号中返回每个参数。
如”$@”用「”」括起来的情况、以”$1” “$2” … “$n” 的形式输出所有参数。
$-显示Shell使用的当前选项,与set命令功能相同。
$?显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。


算术运算符

下表列出了常用的算术运算符,假定变量 a 为 10,变量 b 为 20:

运算符说明举例
+加法expr $a + $b 结果为 30。
-减法expr $a - $b 结果为 -10。
*乘法expr $a \* $b 结果为 200。
/除法expr $b / $a 结果为 2。
%取余expr $b % $a 结果为 0。
=赋值a=$b 将把变量 b 的值赋给 a。
==相等。用于比较两个数字,相同则返回 true。[ $a == $b ] 返回 false。
!=不相等。用于比较两个数字,不相同则返回 true。[ $a != $b ] 返回 true。

注意:条件表达式要放在方括号之间,并且要有空格,例如: [$a==$b] 是错误的,必须写成 [ $a == $b ]。

算术运算符实例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/bin/bash

a=10
b=20

val=`expr $a + $b`
echo "a + b : $val"

val=`expr $a - $b`
echo "a - b : $val"

val=`expr $a \* $b`
echo "a * b : $val"

val=`expr $b / $a`
echo "b / a : $val"

val=`expr $b % $a`
echo "b % a : $val"

if [ $a == $b ]
then
echo "a 等于 b"
fi
if [ $a != $b ]
then
echo "a 不等于 b"
fi

执行脚本,输出结果如下所示:

1
2
3
4
5
6
a + b : 30
a - b : -10
a * b : 200
b / a : 2
b % a : 0
a 不等于 b

注意:⚠️

  • 乘号(*)前边必须加反斜杠()才能实现乘法运算;
  • if…then…fi 是条件语句,后续将会讲解。
  • 在 MAC 中 shell 的 expr 语法是:$((表达式)),此处表达式中的 “*” 不需要转义符号 “\” 。

关系运算符

关系运算符只支持数字,不支持字符串,除非字符串的值是数字

下表列出了常用的关系运算符,假定变量 a 为 10,变量 b 为 20:

运算符说明举例
-eq检测两个数是否相等,相等返回 true。[ $a -eq $b ] 返回 false。
-ne检测两个数是否不相等,不相等返回 true。[ $a -ne $b ] 返回 true。
-gt检测左边的数是否大于右边的,如果是,则返回 true。[ $a -gt $b ] 返回 false。
-lt检测左边的数是否小于右边的,如果是,则返回 true。[ $a -lt $b ] 返回 true。
-ge检测左边的数是否大于等于右边的,如果是,则返回 true。[ $a -ge $b ] 返回 false。
-le检测左边的数是否小于等于右边的,如果是,则返回 true。[ $a -le $b ] 返回 true。

关系运算符实例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#!/bin/bash

a=10
b=20

if [ $a -eq $b ]
then
echo "$a -eq $b : a 等于 b"
else
echo "$a -eq $b: a 不等于 b"
fi
if [ $a -ne $b ]
then
echo "$a -ne $b: a 不等于 b"
else
echo "$a -ne $b : a 等于 b"
fi
if [ $a -gt $b ]
then
echo "$a -gt $b: a 大于 b"
else
echo "$a -gt $b: a 不大于 b"
fi
if [ $a -lt $b ]
then
echo "$a -lt $b: a 小于 b"
else
echo "$a -lt $b: a 不小于 b"
fi
if [ $a -ge $b ]
then
echo "$a -ge $b: a 大于或等于 b"
else
echo "$a -ge $b: a 小于 b"
fi
if [ $a -le $b ]
then
echo "$a -le $b: a 小于或等于 b"
else
echo "$a -le $b: a 大于 b"
fi

执行脚本,输出结果如下所示:

1
2
3
4
5
6
10 -eq 20: a 不等于 b
10 -ne 20: a 不等于 b
10 -gt 20: a 不大于 b
10 -lt 20: a 小于 b
10 -ge 20: a 小于 b
10 -le 20: a 小于或等于 b

布尔运算符

下表列出了常用的布尔运算符,假定变量 a 为 10,变量 b 为 20:

运算符说明举例
!非运算,表达式为 true 则返回 false,否则返回 true。[ ! false ] 返回 true。
-o或运算,有一个表达式为 true 则返回 true。[ $a -lt 20 -o $b -gt 100 ] 返回 true。
-a与运算,两个表达式都为 true 才返回 true。[ $a -lt 20 -a $b -gt 100 ] 返回 false。

布尔运算符实例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/bin/bash

a=10
b=20

if [ $a != $b ]
then
echo "$a != $b : a 不等于 b"
else
echo "$a != $b: a 等于 b"
fi
if [ $a -lt 100 -a $b -gt 15 ]
then
echo "$a 小于 100 且 $b 大于 15 : 返回 true"
else
echo "$a 小于 100 且 $b 大于 15 : 返回 false"
fi
if [ $a -lt 100 -o $b -gt 100 ]
then
echo "$a 小于 100 或 $b 大于 100 : 返回 true"
else
echo "$a 小于 100 或 $b 大于 100 : 返回 false"
fi
if [ $a -lt 5 -o $b -gt 100 ]
then
echo "$a 小于 5 或 $b 大于 100 : 返回 true"
else
echo "$a 小于 5 或 $b 大于 100 : 返回 false"
fi

执行脚本,输出结果如下所示:

1
2
3
4
10 != 20 : a 不等于 b
10 小于 100 且 20 大于 15 : 返回 true
10 小于 100 或 20 大于 100 : 返回 true
10 小于 5 或 20 大于 100 : 返回 false

逻辑运算符

以下介绍 Shell 的逻辑运算符,假定变量 a 为 10,变量 b 为 20:

运算符说明举例
&&逻辑的 AND[ $a -lt 100 && $b -gt 100 ] 返回 false
||逻辑的 OR[ $a -lt 100 || $b -gt 100 ] 返回 true

逻辑运算符实例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/bin/bash

a=10
b=20

if [[ $a -lt 100 && $b -gt 100 ]]
then
echo "返回 true"
else
echo "返回 false"
fi

if [[ $a -lt 100 || $b -gt 100 ]]
then
echo "返回 true"
else
echo "返回 false"
fi

执行脚本,输出结果如下所示:

1
2
返回 false
返回 true

字符串运算符

下表列出了常用的字符串运算符,假定变量 a 为 “abc”,变量 b 为 “efg”:

运算符说明举例
=检测两个字符串是否相等,相等返回 true。[ $a = $b ] 返回 false。
!=检测两个字符串是否相等,不相等返回 true。[ $a != $b ] 返回 true。
-n检测字符串长度是否为0,不为0返回 true。[ -n “$a” ] 返回 true。
str检测字符串是否为空,不为空返回 true。[ $a ] 返回 true。

字符串运算符实例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/bin/bash

a="abc"
b="efg"

if [ $a = $b ]
then
echo "$a = $b : a 等于 b"
else
echo "$a = $b: a 不等于 b"
fi
if [ $a != $b ]
then
echo "$a != $b : a 不等于 b"
else
echo "$a != $b: a 等于 b"
fi
if [ -z $a ]
then
echo "-z $a : 字符串长度为 0"
else
echo "-z $a : 字符串长度不为 0"
fi
if [ -n "$a" ]
then
echo "-n $a : 字符串长度不为 0"
else
echo "-n $a : 字符串长度为 0"
fi
if [ $a ]
then
echo "$a : 字符串不为空"
else
echo "$a : 字符串为空"
fi

执行脚本,输出结果如下所示:

1
2
3
4
5
abc = efg: a 不等于 b
abc != efg : a 不等于 b
-z abc : 字符串长度不为 0
-n abc : 字符串长度不为 0
abc : 字符串不为空

文件测试运算符

文件测试运算符用于检测 Unix 文件的各种属性。

属性检测描述如下:

运算符说明举例
-b file检测文件是否是块设备文件,如果是,则返回 true。[ -b $file ] 返回 false。
-c file检测文件是否是字符设备文件,如果是,则返回 true。[ -c $file ] 返回 false。
-d file检测文件是否是目录,如果是,则返回 true。[ -d $file ] 返回 false。
-f file检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。[ -f $file ] 返回 true。
-g file检测文件是否设置了 SGID 位,如果是,则返回 true。[ -g $file ] 返回 false。
-k file检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。[ -k $file ] 返回 false。
-p file检测文件是否是有名管道,如果是,则返回 true。[ -p $file ] 返回 false。
-u file检测文件是否设置了 SUID 位,如果是,则返回 true。[ -u $file ] 返回 false。
-r file检测文件是否可读,如果是,则返回 true。[ -r $file ] 返回 true。
-w file检测文件是否可写,如果是,则返回 true。[ -w $file ] 返回 true。
-x file检测文件是否可执行,如果是,则返回 true。[ -x $file ] 返回 true。
-s file检测文件是否为空(文件大小是否大于0),不为空返回 true。[ -s $file ] 返回 true。
-e file检测文件(包括目录)是否存在,如果是,则返回 true。[ -e $file ] 返回 true。

变量 file 表示文件”/var/www/runoob/test.sh”,它的大小为100字节,具有 rwx 权限。下面的代码,将检测该文件的各种属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/bin/bash

file="/var/www/runoob/test.sh"
if [ -r $file ]
then
echo "文件可读"
else
echo "文件不可读"
fi
if [ -w $file ]
then
echo "文件可写"
else
echo "文件不可写"
fi
if [ -x $file ]
then
echo "文件可执行"
else
echo "文件不可执行"
fi
if [ -f $file ]
then
echo "文件为普通文件"
else
echo "文件为特殊文件"
fi
if [ -d $file ]
then
echo "文件是个目录"
else
echo "文件不是个目录"
fi
if [ -s $file ]
then
echo "文件不为空"
else
echo "文件为空"
fi
if [ -e $file ]
then
echo "文件存在"
else
echo "文件不存在"
fi

执行脚本,输出结果如下所示:

1
2
3
4
5
6
7
文件可读
文件可写
文件可执行
文件为普通文件
文件不是个目录
文件不为空
文件存在

Shell 流程控制

if else

if

if 语句语法格式:

1
2
3
4
5
6
7
if condition
then
command1
command2
...
commandN
fi

写成一行(适用于终端命令提示符):

1
if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi

末尾的fi就是if倒过来拼写,后面还会遇到类似的。

if else

if else 语法格式:

1
2
3
4
5
6
7
8
9
if condition
then
command1
command2
...
commandN
else
command
fi

if else-if else

if else-if else 语法格式:

1
2
3
4
5
6
7
8
9
if condition1
then
command1
elif condition2
then
command2
else
commandN
fi

以下实例判断两个变量是否相等:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
a=10
b=20
if [ $a == $b ]
then
echo "a 等于 b"
elif [ $a -gt $b ]
then
echo "a 大于 b"
elif [ $a -lt $b ]
then
echo "a 小于 b"
else
echo "没有符合的条件"
fi

输出结果:

1
a 小于 b

if else语句经常与test命令结合使用,如下所示:

1
2
3
4
5
6
7
8
num1=$[2*3]
num2=$[1+5]
if test $[num1] -eq $[num2]
then
echo '两个数字相等!'
else
echo '两个数字不相等!'
fi

输出结果:

1
两个数字相等!

for 循环

for循环一般格式为:

1
2
3
4
5
6
7
for var in item1 item2 ... itemN
do
command1
command2
...
commandN
done

写成一行:

1
for var in item1 item2 ... itemN; do command1; command2… done;

当变量值在列表里,for循环即执行一次所有命令,使用变量名获取列表中的当前取值。命令可为任何有效的shell命令和语句。in列表可以包含替换、字符串和文件名。

in列表是可选的,如果不用它,for循环使用命令行的位置参数。

例如,顺序输出当前列表中的数字:

1
2
3
4
for loop in 1 2 3 4 5
do
echo "The value is: $loop"
done

输出结果:

1
2
3
4
5
The value is: 1
The value is: 2
The value is: 3
The value is: 4
The value is: 5

顺序输出字符串中的字符:

1
2
3
4
for str in 'This is a string'
do
echo $str
done

输出结果:

1
2
3
4
This
is
a
string

while 语句

while循环用于不断执行一系列命令,也用于从输入文件中读取数据;命令通常为测试条件。其格式为:

1
2
3
4
while condition
do
command
done

以下是一个基本的while循环,测试条件是:如果int小于等于5,那么条件返回真。int从0开始,每次循环处理时,int加1。运行上述脚本,返回数字1到5,然后终止。

1
2
3
4
5
6
7
#!/bin/bash
int=1
while(( $int<=5 ))
do
echo $int
let "int++"
done

运行脚本,输出:

1
2
3
4
5
1
2
3
4
5

无限循环

无限循环语法格式:

1
2
3
4
5
6
7
8
9
10
while :
do
command
done
或者

while true
do
command
done

或者

1
for (( ; ; ))

until 循环

until 循环执行一系列命令直至条件为 true 时停止。

until 循环与 while 循环在处理方式上刚好相反。

一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下,until 循环更加有用。

until 语法格式:

1
2
3
4
until condition
do
command
done

condition 一般为条件表达式,如果返回值为 false,则继续执行循环体内的语句,否则跳出循环。

以下实例我们使用 until 命令来输出 0 ~ 9 的数字:

1
2
3
4
5
6
7
8
9
#!/bin/bash

a=0

until [ ! $a -lt 10 ]
do
echo $a
a=`expr $a + 1`
done

运行结果:

1
2
3
4
5
6
7
8
9
10
0
1
2
3
4
5
6
7
8
9

case

Shell case语句为多选择语句。可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。

case语句格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
case 值 in
模式1)
command1
command2
...
commandN
;;
模式2)
command1
command2
...
commandN
;;
esac

case工作方式如上所示。取值后面必须为单词in,每一模式必须以右括号结束。取值可以为变量或常数。匹配发现取值符合某一模式后,其间所有命令开始执行直至 ;;。

取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号 * 捕获该值,再执行后面的命令。

下面的脚本提示输入1到4,与每一种模式进行匹配:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
echo '输入 1 到 4 之间的数字:'
echo '你输入的数字为:'
read aNum
case $aNum in
1) echo '你选择了 1'
;;
2) echo '你选择了 2'
;;
3) echo '你选择了 3'
;;
4) echo '你选择了 4'
;;
*) echo '你没有输入 1 到 4 之间的数字'
;;
esac

输入不同的内容,会有不同的结果,例如:

1
2
3
4
输入 1 到 4 之间的数字:
你输入的数字为:
3
你选择了 3

esac

case的语法和C family语言差别很大,它需要一个esac(就是case反过来)作为结束标记,每个case分支用右圆括号,用两个分号表示break。

跳出循环

在循环过程中,有时候需要在未达到循环结束条件时强制跳出循环,Shell使用两个命令来实现该功能:break和continue。

break命令

break命令允许跳出所有循环(终止执行后面的所有循环)。

下面的例子中,脚本进入死循环直至用户输入数字大于5。要跳出这个循环,返回到shell提示符下,需要使用break命令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
while :
do
echo -n "输入 1 到 5 之间的数字:"
read aNum
case $aNum in
1|2|3|4|5)
echo "你输入的数字为 $aNum!"
;;
*)
echo "你输入的数字不是 1 到 5 之间的! 游戏结束"
break
;;
esac
done

执行以上代码,输出结果为:

1
2
3
4
输入 1 到 5 之间的数字:3
你输入的数字为 3!
输入 1 到 5 之间的数字:7
你输入的数字不是 1 到 5 之间的! 游戏结束

continue命令

continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环,与C语言一样。

对上面break的例子进行修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash
while :
do
echo -n "输入 1 到 5 之间的数字:"
read aNum
case $aNum in
1|2|3|4|5)
echo "你输入的数字为 $aNum!"
;;
*)
echo "你输入的数字不是 1 到 5 之间的! 游戏结束"
continue
echo "游戏结束"
;;
esac
done

运行代码发现,当输入大于5的数字时,该例中的循环不会结束,语句 echo “游戏结束” 永远不会被执行。


四、内存纠错(指出错误、修改错误) 10’

==内存实验代码相关内容搞清楚==

  • 代码区(text segment)。加载的是可执行文件代码段,其加载到内存中的位置由加载器完成。
  • 全局初始化数据区/静态数据区(Data Segment)。加载的是可执行文件数据段,存储于数据段(全局初始化,静态初始化数据)的数据的生存周期为整个程序运行过程。
  • 未初始化数据区(BSS)。加载的是可执行文件BSS段,位置可以分开亦可以紧靠数据段,存储于数据段的数据(全局未初始化,静态未初始化数据)的生存周期为整个程序运行过程。
  • 栈区(stack)。由编译器自动分配释放,存放函数的参数值、返回值、局部变量等。在程序运行过程中实时加载和释放,因此,局部变量的生存周期为申请到释放该段栈空间。
  • 堆区(heap)。用于动态内存分配。堆在内存中位于BSS区和栈区之间。一般由程序员分配和释放,若程序员不释放,程序结束时有可能由OS回收。

常见的内存错误:

  • 返回局部变量地址错误
  • 临时空间过大:如定义数组的大小过大
  • 空指针
  • 滥用
  • 泄漏:通常指堆内存泄露。即通过malloc、realloc和new等函数分配内存造成的
  • 出现原因:堆内存分配后,未释放;堆内存分配后,释放顺序不当

例题⚠️⚠️⚠️

  • 示例1:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void GetMemory(char *p, int num)
    {
    p = (char *)malloc(sizeof(char) * num);
    }
    void Test(void)
    {
    char *str = NULL;
    GetMemory(str, 100);
    strcpy(str, "hello");
    }

    ==错误:==

    (1)空指针非法操作。因为str与p之间是值传递,在函数GetMemory调用结束后,p分配空

    (2)在函数GetMemory中分配的空间没有回收,导致内存泄露。

    改正:

    参见示例2和示例3。

  • 示例2:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    void GetMemory2(char **p, int num)
    {
    *p = (char *)malloc(sizeof(char) * num);
    }

    void Test2(void)
    {
    char *str = NULL;
    GetMemory2(&str, 100);
    strcpy(str, "hello");
    cout<< str << endl;
    free(str);
    }

    ==正确==

  • 示例3

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    char *GetMemory3(int num)
    {
    char *p = (char *)malloc(sizeof(char) * num);
    return p;
    }

    void Test3(void)
    {
    char *str = NULL;
    str = GetMemory3(100);
    strcpy(str, "hello");
    cout<< str << endl;
    free(str);
    }

    ==正确==

  • 示例4

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    char *GetString(void)
    {
    char p[] = "hello world";
    return p;
    }

    void Test4(void)
    {
    char *str = NULL;
    str = GetString();
    cout<< str << endl;
    }

    ==错误:==

    (1)出现乱码打印。因为在函数GetString中,p数组拷贝了字符串常量“hello world”的值,但函数调用结束后,p数组回收导致这段空间内容被篡改,但p数组首地址确能成功返回指针变量str中,所有str可以输出,但内容确不是”hello world”。

    改正:

    参见示例5。

  • 示例5

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    char *GetString2(void)
    {
    char *p = "hello world";
    return p;
    }

    void Test5(void)
    {
    char *str = NULL;
    str = GetString2();
    cout<< str << endl;
    }

    ==正确==


五、问答题 40’

  • ls -l⚠️⚠️⚠️
    ls -l 详解

  • 进程

  • 获取进程的各种ID (非负数)

    1
    2
    3
    4
    5
    6
    7
    8
    #include <sys/types.h>
    #include <unistd.h>
    pid_t getpid(void);
    pid_t getppid(void);
    uid_t getuid(void); //获得进程的实际用户ID
    uid_t geteuid(void); /获得进程的有效用户ID
    gid_t getgid(void); //获得进程的实际组ID
    gid_t getegid(void); //获得进程的有效组ID
  • 创建进程 (fork)

    1
    2
    #include <unistd.h>
    pid_t fork(void);
  • 例题⚠️⚠️⚠️

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    #include <stdio.h>
    #include <signal.h>
    #include <stdlib.h>
    #include <unistd.h>

    int hours = 0;
    int seconds = -1;
    int minutes = 0;

    void handler(int signal) {
    seconds++;
    if (seconds == 60) {
    minutes++;
    seconds = 0;
    if (minutes == 60) {
    hours++;
    minutes = 0;
    if (hours == 24) {
    hours = 0;
    }
    }
    }
    printf("\r%02d:%02d:%02d", hours, minutes, seconds);
    fflush(stdout);//清空缓存
    }

    int main() {
    pid_t pid = fork();//创建子进程
    pid_t ppid;
    if (pid == 0) {
    ppid = getppid();//获取父进程的id
    while (1) {
    kill(ppid, SIGALRM);//接受信号
    sleep(1);
    }
    } else if (pid != -1) {
    signal(SIGALRM, handler);//安装SIGALRM信号
    while (1) {
    pause();//等待接受信号
    }
    } else {
    printf("fork error!");
    }
    return 0;
    }

问题:⚠️有几个进程?描述整个过程⚠️

  • 线程
  • 编译,不要忘了-lpthread⚠️⚠️⚠️

    1
    gcc -o test test.c -lpthread
  • 线程控制函数⚠️⚠️⚠️

    • 创建线程
      pthread_create

      1
      2
      3
      4
      5
      6
      7
      8
      #include <pthread.h>
      int pthread_create(pthread_t * tidp, const pthread_attr_t *attr, void *(*start_rtn)(void *), void *arg);
      // 返回:成功返回0,出错返回错误编号
      参数:
      参数1:是一个传出参数,用于保存成功创建线程之后对应的线程id。
      参数2:表示线程的属性,通常默认传NULL,如果想使用具体的属性也可以修改具体的参数。
      参数3:函数指针,一个指向函数的指针。指向创建线程所执行函数的入口地址,函数执行完毕,则线程结束。
      参数4:线程主函数执行期间所使用的参数。

      当pthread_create函数返回成功时,有tidp指向的内存被设置为新创建线程的线程ID,其类型pthread_t定义为:

      1
      2
      #include <bits/pthreadtypes.h>
      typedef unsigned long int pthread_t;

      attr参数用于设置各种不同的线程属性,为NULL时表示默认线程属性。新创建的线程从start_rtn函数的地址开始运行,该函数只有一个无类型指针的参数arg,如果需要向start_rtn函数传入的参数不止一个,可以把参数放入到一个结构中,然后把这个结构的地址作为arg的参数传入。

      线程创建时并不能保证哪个线程会先运行:是新创建的线程还是调用线程。新创建的线程可以访问调用进程的地址空间,并且继承调用线程的浮点环境和信号屏蔽字,但是该线程的未决信号集被清除。那什么是未决信号呢,信号产生到信号被处理这段时间间隔,称信号是未决的。

    • 终止线程
      pthread_exit

      1
      2
      3
      4
      #include <pthread.h>
      void pthread_exit(void *rval_ptr);
      // 线程终止
      参数:retval表示线程的退出状态,通常穿NULL。当要求传出具体的退出状态时,可以使用retval。

      线程在结束时最好调用该函数,以确保安全、干净的退出。pthread_exit函数通过rval_ptr参数向调用线程的回收者传递退出信息,进程中的其他线程可以调用pthread_join函数访问到这个指针。

      pthread_exit执行完后不会返回到调用者,而且永远不会失败。

      线程可以通过以下三种方式退出,在不终止整个进程的情况下停止它的控制流:

      • 线程只是从启动过程中退出,返回值是线程的退出码
      • 线程可以被同一进程中的其他线程取消
      • 线程调用pthread_exit
    • 等待线程
      pthread_join

      1
      2
      3
      4
      #include <pthread.h>
      int pthread_join(pthread_t thread, void **rval_ptr);
      // 返回:成功返回0,出错返回错误代码
      参数: pthread为线程id,retval为线程的状态。可以与pthread_exit()结合使用。

      调用该函数的线程将挂起等待,为阻塞的状态。直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:

      1. 如果thread线程通过return返回,retval所指向的单元里存放的是thread线程函数的返回值。
      2. 如果thread线程被别的线程调用pthread_cancel异常终止掉,retval所指向的单元里存放的是常数PTHREAD_CANCELED。
      3. 如果thread线程是自己调用pthread_exit终止的,retval所指向的单元存放的是传给pthread_exit的参数。
      4. 如果对thread线程的终止状态不感兴趣,可以传NULL给retval参数。
  • 其他的内容嘛,自己想我为什么不写*😄😄😄

  • makefile

  • 多说无义,直接上题⚠️⚠️⚠️

    阅读Makefile文件,回答问题:

    如果注释掉all : libmys.so语句的话,需要输入指定执行规则make libmys.so运行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    all : libmys.so
    SRC=f1.c f2.c f3.c
    TGT=$(patsubst %.c,%.o,$(SRC)) #子串替换
    %.o : %.c #模式规则 所有.c通过执行gcc指令获得.o文件
    cc -c $? #代表依赖文件f1.c f2.c f3.c
    libmys.so : $(TGT)
    cc -shared -o $@ $(TGT)
    clean:
    rm -f $(TGT)

    回答以下问题:

    • A:

      • 此Makefile文件的主要功能是什么?

        1
        创建名为libmys.so的动态库
      • 此Makefile文件包含多少个规则?它们分别是什么?

        1
        2
        4个;分别是 all 、 %.o 、  libmys.so 、 clean
        (有几个冒号,就有几个规则)
      • 使用此Makefile文件可以生成目标文件f2.o吗?为什么?

        1
        可以生成f2.o  因为有%.o : %.c 这一模式规则,该规则	使所有的.c的依赖文件编译生成.o的目标文件。
      • 此Makefile中,请指出存在的伪目标名称。

        1
        all、clean
      • 请写出$(TGT)的值。

        1
        $(TGT)的值为:f1.o f2.o f3.o
    • B:

      • 此Makefile文件中,可以生成共享库,请指出共享库名字。

        1
        libmys.so
      • 如果测试该生成共享库的源文件test.c,请将它编译生成可执行程序并运行。

        1
        2
        3
        gcc test.c -o test -lmys -L ./
        LD_LIBRARY_PATH=./
        ./test
      • 此Makefile文件中,除了显式规则,还使用了哪种规则,请指出并解释。

        1
        2
        3
        4
        还使用了模式规则:
        %.o : %.c
        cc -c $?
        该规则使所有的.c的依赖文件编译生成.o的目标文件。
      • 此Makefile文件中,all表示什么目标?

        1
        伪目标
      • 此Makefile中,请指出使用的函数并解释其功能。

        1
        TGT=$(patsubst %.c,%.o,$(SRC)) :运用patsubst(替换通配符),将$(SRC)中所有的末尾为.c的字符串替换为末尾为.o的字符串。
    • C:

      • 此Makefile文件的主要功能是什么,如何通过命令执行出结果?

        1
        生成共享库libmys.so,执行指令make 或者make all
      • 请描述该Makefile文件获得执行结果的过程

        1
        2
        3
        4
        ① 声明所需要的文件名
        ② 为f1.c f2.c f3.c生成.o文件
        ③ 将所生成的.o文件生成共享库
        ④ 清除中间生成的文件
      • $?的值是什么?

        1
        f1.c f2.c f3.c
-------------本文结束感谢您的阅读-------------

本文标题:【Linux】Linux期末复习

文章作者:FisherCloud/鱼摆摆

发布时间:2019年03月08日 - 21:27

最后更新:2019年03月11日 - 15:35

原始链接:http://fishercloud.tech/2019/03/08/Linux期末复习/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

0%