Exam - Linux程序设计

Linux考试重点

写在前面:
Linux程序设计这门课确实能学到一些实用的东西。但是考试不敢恭维…感觉还是往年卷重要一点吧)))

​ 20届试卷 5道单选+文件锁类型并举例相关系统调用+内核和应用程序的区别+编程题(使用系统调用复制a文件的后一半内容到b文件) +华为openEuler

1. Ch1 Linux Basics

1.1 谈谈你对linux的理解、什么是linux、历史、发行版、协议(开放性 10分以内)

​ Linux是根据GNU通用公共许可证开发的自由、免费Unix类型的操作系统。

​ 特点:开源、受欢迎、支持大多数可用平台

​ GPL协议,即GNU通用公共许可证。

1.2 安装Linux的步骤不考,分区的形式要知道。MBR的性质、GPT的好处(知道)

(以下来自ChatGPT)

  • 分区形式:
    • Linux分区的形式通常使用磁盘分区表(partition table)来管理磁盘上的分区。常用的磁盘分区表包括MBR(Master Boot Record)和GPT(GUID Partition Table)。
      • MBR是一种早期的磁盘分区表,它将磁盘划分为四个主分区或三个主分区和一个扩展分区。扩展分区可以再被划分为多个逻辑分区,这种方式限制了磁盘上的分区数目。
      • GPT是现代磁盘分区表,它支持更大的磁盘容量和更多的分区,最多可以划分128个分区。GPT也支持备份分区表来提高数据可靠性,同时支持UEFI(Unified Extensible Firmware Interface)引导方式。
    • 在Linux系统中,常见的分区类型包括:
      • 根分区(/):包含操作系统和所有系统文件的分区。
      • 交换分区(swap):用于内存交换空间,可以提高系统的性能。
      • /boot分区:包含操作系统内核和引导加载器的分区。
      • /home分区:包含用户文件和个人设置的分区。
      • /var分区:包含系统日志和临时文件的分区。
      • 数据分区(/data):用于存储其他数据的分区,如数据库和应用程序文件。

​ 以上是一些常见的分区类型,实际上,用户可以根据自己的需求和系统架构进行更细粒度的分区设置。

  • MBR的性质:
    • MBR(Master Boot Record)是一种早期的磁盘分区表,用于在硬盘上存储分区信息和引导加载器(boot loader)。以下是MBR的一些性质:
      • MBR是一个512字节的区域,通常位于硬盘的第一个扇区(sector),也就是0磁道0扇区。
      • MBR可以划分磁盘为最多4个主分区或3个主分区和1个扩展分区。扩展分区可以被划分为多个逻辑分区,但这些逻辑分区不能被用作操作系统启动分区。
      • MBR中存储了分区表和引导加载程序(boot loader),分区表用于记录分区的起始和结束扇区的位置。引导加载程序通常位于MBR的最后446个字节,用于引导加载操作系统。
      • MBR的分区表只能记录最多4个分区,这意味着它存在分区数目的限制。同时,MBR也无法支持大于2TB的磁盘。
      • MBR是一种古老的分区表,现在已经被GPT(GUID Partition Table)取代。但由于其兼容性和历史原因,仍然被一些操作系统使用。

​ 总之,MBR是一种古老的磁盘分区表,由于其分区数目的限制和对大容量磁盘的支持问题,现已被GPT所取代。

  • GPT的优点:

    • GPT(GUID Partition Table)是一种现代的磁盘分区表,相比于MBR(Master Boot Record),具有以下优点:

      • 支持更大的磁盘容量:MBR只能支持最大2TB的磁盘容量,而GPT可以支持超过9.4ZB的磁盘容量,这使得GPT可以处理更大容量的磁盘。
      • 支持更多的分区:MBR只能支持最多4个主分区或3个主分区和1个扩展分区,而GPT最多可以支持128个分区。
      • 支持备份分区表:GPT可以在磁盘上存储备份分区表,这样即使主分区表受到损坏,也可以使用备份分区表来还原磁盘分区信息。
      • 支持更安全的启动方式:GPT支持UEFI(Unified Extensible Firmware Interface)引导方式,这种启动方式相比MBR的传统BIOS引导方式更安全和更灵活,支持更多的操作系统和更高级的安全性特性,例如Secure Boot。
      • 支持更多的操作系统:GPT支持更多的操作系统,包括Windows、Linux、macOS等。而MBR由于其分区数目和磁盘容量限制,只能支持较少的操作系统。

      综上所述,GPT相比于MBR拥有更高的磁盘容量和分区数目限制,支持备份分区表、更安全的启动方式和更多的操作系统,这些优点使得GPT更加适合现代的计算机系统。


1.3 文件系统的概念

  • 操作系统中负责访问和管理文件的部分
  • 文件及其某些属性的集合。它为引用这些文件的文件序列号提供了名称空间。(susv3)

Linux中的文件系统:

  1. VFS
    1. VFS(Virtual File System)是指一种抽象层,它隐藏了操作系统中不同文件系统的具体实现细节,提供了一个统一的文件系统接口给用户和应用程序使用。VFS的作用是将不同的文件系统以相同的方式呈现给用户和应用程序,从而简化文件访问的复杂性。
  2. EXT2,EXT3,FAT32等
    1. 以上都是文件系统类型

1.4 知道GRUB,所在的位置、起到什么作用

GRUB(GRand Unified Bootloader)是一款常用的开源多操作系统引导程序,常用于Linux系统中作为操作系统启动程序。

在BIOS系统中,GRUB通常存储在MBR中,MBR是硬盘的第一个扇区,其中包含引导程序、分区表和磁盘签名等信息。GRUB的配置文件通常存储在/boot/grub/grub.cfg或/etc/grub.conf文件中,该文件包含GRUB的启动选项、操作系统的位置和启动参数等信息。

p9CrIx0.png


1.5 配置菜单

在Ubuntu中,可以使用update-grub命令来生成菜单配置文件。update-grub会自动检测系统中安装的操作系统和内核,然后生成GRUB菜单配置文件/boot/grub/grub.cfg。

要编辑Linux中的菜单,可以编辑GRUB配置文件/etc/default/grub和/etc/grub.d/目录中的脚本文件。其中,/etc/default/grub文件包含GRUB的默认配置选项,如超时时间、默认启动项等;/etc/grub.d/目录中的脚本文件包含了生成菜单的具体配置信息,如Ubuntu、Debian等发行版会提供一些用于检测并添加操作系统、内核和其他可启动项的脚本文件。

编辑完成后,使用update-grub命令重新生成GRUB的菜单配置文件即可生效。在编辑前建议备份原配置文件以防止配置错误造成系统启动问题。

p9CrTMV.pngp9CrHqU.png
这是一个Ubuntu操作系统的引导配置文件(通常称为GRUB配置文件),用于启动Ubuntu系统并加载特定的内核版本(2.6.20-16-generic)。
“root (hd0,1)”指定Ubuntu根目录的设备位置,其中"hd0,1"表示第一个硬盘的第二个分区(硬盘和分区号从0开始)。
“kernel /boot/vmlinuz-2.6.20-16-generic”指定要加载的内核文件的路径和文件名。
“root=UUID=3f784cd9-516f-4808-a601-b19356f6bdea”指定Ubuntu根文件系统的唯一标识符(UUID),以确保引导程序能够正确找到和加载Ubuntu操作系统的根目录。
“ro”指定将根文件系统挂载为只读模式,以确保文件系统的完整性。
“quiet splash”指定内核启动时显示的信息级别和显示Ubuntu启动画面。
“locale=zh_CN”指定系统语言环境为中文。 "vga=0x318"指定显示分辨率为 1024x768 。
“initrd /boot/initrd.img-2.6.20-16-generic”指定初始化RAM磁盘(initrd)的路径和文件名,该文件包含启动系统所需的驱动程序和文件系统工具。
这是一个与Microsoft Windows XP Professional相关的引导配置代码。这些指令通常用于操作系统启动引导程序(例如GRUB或LILO)中。
“root (hd0,0)” 指定操作系统所在的硬盘和分区。在这个例子中,操作系统位于第一块硬盘的第一个分区(也就是C:\)。
**“savedefault” 命令告诉引导程序在下次重启时记住上次选择的引导项,这样就不需要每次都手动选择操作系统了。
“makeactive” 命令将选择的分区标记为“活动分区”,这是在多重引导系统中必需的操作,以指示引导程序在此分区中查找操作系统文件。
“chainloader +1” **命令加载选择的分区中的引导扇区,并尝试引导该操作系统。

1.6 编译开源软件的流程要知道automake和cmake

AutomakeCMake是两个常用的自动化构建工具,主要用于生成Makefile以便编译、构建和安装软件。

Automake是GNU Autotools套件中的一部分,它使用Makefile.am文件来描述软件包的构建规则。 Automake提供了一个简单的、易于维护的方法来自动生成Makefile,并支持自动检测系统和库依赖关系。但是,Automake使用基于文本的Makefile.am文件,这种文件格式可能需要一些学习成本。

CMake是一个跨平台的开源构建工具,它使用CMakeLists.txt文件来描述软件包的构建规则。 CMake可以生成各种构建系统,包括Makefile、Visual Studio、Xcode等。 CMake还提供了一个跨平台的配置系统,可以自动检测系统和库依赖关系,并提供了一个灵活的变量系统,可以轻松地配置软件包。

p9CrqZF.png

  • tar zxvf application.tar.gz - 这个命令解压缩tarball,将源代码提取到一个名为“application”的目录中。'z’选项表示使用gzip进行压缩,'x’选项表示提取文件,'v’选项表示在命令行中显示进度,'f’选项表示使用文件名作为参数。

  • cd application - 这个命令进入提取的应用程序源代码的目录。

  • ./configure - 这个命令运行一个名为“configure”的脚本,用于自动检测系统和库依赖关系,并生成一个Makefile,用于编译和构建软件包。

  • make - 这个命令根据Makefile文件,编译源代码并生成可执行文件。

  • su - - 这个命令切换到root用户,以便安装可执行文件。

  • make install - 这个命令将可执行文件和其他必要的文件安装到系统中,使其可以在任何地方运行。

p9CrLa4.png

  • tar zxvf application.tar.gz - 这个命令解压缩tarball,将源代码提取到一个名为“application”的目录中。'z’选项表示使用gzip进行压缩,'x’选项表示提取文件,'v’选项表示在命令行中显示进度,'f’选项表示使用文件名作为参数。

  • cd application - 这个命令进入提取的应用程序源代码的目录。

  • mkdir build - 这个命令创建一个名为“build”的目录,用于在其中构建应用程序。

  • cd build - 这个命令进入build目录,以便在其中构建应用程序。

  • cmake .. - 这个命令运行CMake,使用CMakeLists.txt文件来描述应用程序的构建规则,并生成Makefile。'…'表示上一级目录,即应用程序的根目录。

  • make VERBOSE=1 - 这个命令根据Makefile文件,编译源代码并生成可执行文件。VERBOSE=1选项表示在命令行中显示详细的构建信息,便于调试和故障排除。

  • su - - 这个命令切换到root用户,以便安装可执行文件。

  • make install - 这个命令将可执行文件和其他必要的文件安装到系统中,使其可以在任何地方运行。


1.7 Some Basic Linux Commands的命令需要掌握

  • 命令行提示符

    • $ :普通用户
    • # : 根用户
  • ls [options] [directory]

    • -a 显示所有文件,包括隐藏文件。
    • -l 以长格式显示文件信息,包括文件类型、权限、所有者、大小、修改时间等。
    • -h-l 参数一起使用时,以人类可读的格式显示文件大小。
    • -R 递归地列出子目录中的文件和目录。
    • -t 以修改时间排序,最新的文件或目录排在最前面。
    • -S 以文件大小排序,最大的文件或目录排在最前面。
    • -r 反向排序。
  • passwd [options] [username]:更改密码

    • -l 锁定用户的密码。
    • -u 解锁用户的密码。
    • -d 删除用户的密码,使其可以无密码登录。
    • -e 强制用户在下次登录时更改密码。
  • mkpasswd [options]:生成随机密码

    • -m 指定密码生成算法,可选值包括 desmd5sha-256sha-512 等。
    • -S 指定用于生成随机盐值的字符集。
    • -R 指定生成的密码字符串中是否包含随机盐值。
    • -s 不显示密码字符串,仅显示命令执行结果。
    • -P 显示密码生成命令的可重复性提示信息。
  • date [options] [format]:显示当前系统日期和时间

    • +%Y-%m-%d 显示年份、月份和日期,例如 “2023-04-07”。
    • +%H:%M:%S 显示小时、分钟和秒数,例如 “14:30:00”。
    • -d 指定要显示的日期和时间,可以是相对于当前时间的时间量或指定的日期和时间字符串。
    • -u 显示协调世界时(UTC)时间而不是本地时间。
  • cal [options] [month] [year]:显示指定月份或全年的日历信息

    • -1 显示指定月份的日历信息,一行显示一周。
    • -3 显示指定月份前一个月、当前月和后一个月的日历信息。
    • -m 显示指定月份的日历信息,一行显示一周。
    • -y 显示指定年份的全年日历信息。
    • -h 显示帮助信息。
  • who [options]:显示当前登录系统的用户信息

    • -a 显示完整的登录信息,包括终端、登录时间、登录来源和当前进程等。
    • -H 显示标题信息,包括列名和单位等。
    • -q 仅显示登录用户的数量,不显示用户信息。
  • finger [options] [user]:显示指定用户的详细信息

    • -s 仅显示用户名、真实姓名和终端等基本信息,不显示其他详细信息。
    • -l 显示完整的用户信息,包括登录时间、登录来源、邮件和电话等。
    • -m 发送邮件给指定用户。
  • clear:清除屏幕

  • echo [options] [string]:用于在终端中输出文本内容

    • -e 允许输出特殊字符,如换行符 \n 和制表符 \t 等。
    • -n 不输出行末的换行符。
    • -E 禁止输出特殊字符的转义。
      • echo "Hello, $USER":输出包含变量的字符串。
      • VAR="Hello, World!"; echo $VAR:定义一个变量并输出它的值。
  • write user [tty]:用于向另一个用户或终端发送消息

  • talk user [tty]:可以启动一个新的交互窗口,让用户可以直接在该窗口中进行实时交流

  • wall [message]:会向所有登录用户发送消息,而不是只发送给指定用户

  • mesg [y | n]:用于控制是否允许其他用户向当前用户发送消息

    • y 表示允许其他用户向当前用户发送消息,n 表示禁止其他用户向当前用户发送消息。
  • pwd:用于显示当前工作目录的路径

    • 不需要任何参数,直接在终端中输入 pwd 即可输出当前工作目录的完整路径。
  • cd:用于更改当前的工作目录

  • mkdir:创建目录

  • rmdir:删除目录

  • touch [filename]:用于创建新文件或更改已有文件的访问和修改时间戳

    • 如果文件不存在,则会创建一个新文件;如果文件已经存在,则会修改该文件的时间戳
  • cp SOURCE DEST:用于将文件或目录从一个位置复制到另一个位置

    • 第一个参数是要复制的源文件或目录。
    • 第二个参数是要将其复制到的目标位置。
  • mv:用于将文件或目录从一个位置移动到另一个位置,也可以用于重命名文件或目录

    • 第一个参数是要移动或重命名的源文件或目录。
    • 第二个参数是要将其移动到的目标位置或新名称。
  • ln:用于创建硬链接或软链接

    • -s:创建软链接(符号链接)
    • -f:强制创建链接,即使目标文件已经存在
    • -v:显示创建链接的详细信息
    • -i:在创建链接前提示用户是否覆盖现有文件
    • 硬链接是指在文件系统中创建一个文件的别名,它与原始文件具有相同的 inode 和权限。删除原始文件并不会影响硬链接文件,因为它们本质上是同一个文件。硬链接不能跨越不同的文件系统。
    • 软链接是指创建一个指向原始文件或目录的指针或快捷方式。符号链接文件包含指向原始文件或目录的路径,而不是实际的数据。如果原始文件或目录被删除或移动,符号链接将不再有效。软链接可以跨越不同的文件系统。
  • rm [选项] 文件名/目录名:用于删除文件或目录

    • -f:强制删除,不显示提示信息。
    • -r:递归删除目录及其内容。
    • -i:交互式删除,删除前逐一询问是否确定删除。
    • -v:显示详细的删除过程。
  • cat [选项] [文件名]:用于显示文件的内容

    • -n:显示行号。
    • -b:显示非空行号。
    • -s:合并多个空行为一个空行。
    • -v:显示非打印字符。
  • more [选项] [文件名]:按页显示文件内容

    • -d:显示“–More–”提示信息,等待用户输入。
    • -f:将Ctrl-L作为清屏命令。
    • -n:指定显示的行数。
    • -p:指定显示的起始行数。
    • -s:将连续的多个空行合并为一个。
  • less [选项] [文件名]

    • -N:显示行号。
    • -S:不换行显示。
    • /关键字:搜索文件内容中的关键字。
    • q:退出less命令。
  • chmod [选项] 模式 文件名/目录名:用于修改文件或目录的权限

    • -R:递归修改目录及其子目录下的所有文件权限。
    • -v:显示修改的详细信息。

1.8 七种文件类型、目录结构(根目录下的主要目录)、文件权限(chmod、ls -l的各个字段)需要掌握

  • 文件类型:
    • 普通文件( regular file )
      • 文本或代码数据; 没有特别的内部结构
    • 字符设备文件 ( character special file )
    • 块设备文件 ( block special file )
      • 特殊文件:代表硬件或逻辑设备
      • 位于名为/dev的目录中
    • 数据接口文件 ( socket )
      • 数据接口文件,最通常工行在/var/run这个目录中看到这种文件类型。
    • 符号链接文件 ( symbolic link )
      • 软链接:类似windows上的快捷方式
      • 硬链接:同一个文件有两个文件名,创建出来的硬链接不占用磁盘空间和inode号
    • 目录文件 ( Directory )
      • 该目录的文件列表
    • 管道文件 ( fifo )
      • 主要用于进程间通信

1.9. 目录结构

  1. 所有Linux目录都包含在一个虚拟的"统一文件系统"中。
  2. 物理设备安装在安装点上
    1. 软盘
    2. 硬盘分区
    3. CD-ROM驱动器

  • /boot:内核、bootloader的配置,包括引导加载程序相关的文件。内核的initrd、vmlinux、grub文件位于/boot下。

  • /etc:系统的配置文件所在地,下载软件的配置文件在也在这里,包含所有程序所需的配置文件

  • /bin:程序文件夹,包含二进制可执行文件,例如ls,其实是在执行一个程序;也有一部分程序在/usr/bin(在我的linux上,/bin是/usr/bin的软链接)

  • /mnt挂载目录,临时挂载目录,系统管理员可以挂载文件系统。

  • /sbin:系统二进制文件,但是这个目录下的Linux命令通常由系统管理员使用,对系统进行维护,例如ifconfig/fdisk也有部分程序在/sbin,例如分区命令fdisk

  • /usr:资源文件夹(和编程相关的);编译器、默认的头文件、系统中的库文件,包含二进制文件、库文件、文档和二级程序的源代码

  • /usr/bin中包含用户程序的二进制文件。/bin

  • /usr/sbin中包含系统管理员的二进制文件。/sbin

  • /usr/lib中包含了/usr/bin/usr/sbin用到的库。

  • /usr/local中包含了从源安装的用户程序。

  • /lib:系统库。包含支持位于/bin和/sbin下的二进制文件的库文件;库文件名为 ld*或lib*.so.*

  • /proc:包括系统进行相关信息。这是一个虚拟的文件系统,包含有关正在运行的进程的信息;系统资源以文本信息形式存在。

  • /var:系统里的可变数据,变量文件,并不是存放在磁盘上的数据,一般是存放在内存中的数据。

  • 系统日志文件/var/log

  • 包和数据库文件/var/lib

  • 电子邮件/var/mail

  • 打印队列/var/spool

  • 锁文件/var/lock

  • 多次重新启动需要的临时文件/var/tmp

  • /dev:包含设备文件,这些包括终端设备、USB或连接到系统的任何设备。例如/dev/tty1

  • /tmp:包含系统和用户创建的临时文件,当系统重新启动时,这个目录下的文件都将被删除。

  • /home:用home目录来存储他们的个人档案。

  • /opt:可选的附加应用程序

  • /media:用于挂载可移动设备的临时目录。举例来说,挂载CD-ROM的/media/cdrom,挂载软盘驱动器的/media/floppy

  • /srv:srv代表服务。包含服务器特定服务相关的数据。

  • 修改环境变量PATH,临时修改可以直接PATH=$PATH:/bin,但是要永久生效得修改配置文件/etc/profile


1.10 文件权限

  • 文件权限可帮助您保护文件免受他人侵害系统上的用户

  • 三个访问级别:

    • 用户:创建文件的用户
    • 组:拥有文件的组中的所有用户
    • 其他:其他
  • 三个权限:

    • 读取®:读取文件内容或列表内容目录
    • 写(w):更改文件内容或创建/删除文件在目录中
    • 执行(x):以程序执行文件或使用目录作为活动目录
  • 查看文件权限

    • 查看文件权限: ls -l
    • 每一个用户对于文件都有4个八进制数
    • 默认文件权限:
      • File: -rw-r–r-- 644
      • Directory: drwxr-xr-x 755


例如:-rw-r--r--

  • 第一个字符表示文件类型(普通文件为“-”,目录为“d”,符号链接为“l”等)。

  • 接下来的三个字符(“rw-”)表示文件所有者的权限。在这个例子中,所有者具有读和写权限,但没有执行权限。

  • 接下来的三个字符(“r–”)表示文件所属组的权限。在这个例子中,组具有读权限,但没有写或执行权限。

  • 最后三个字符(“r–”)表示所有其他用户的权限。在这个例子中,所有其他用户具有读权限,但没有写或执行权限。

  • 总的来说,这个例子中的文件权限是:

    • 所有者:读和写
    • 组:读
    • 其他用户:读
  • 更改权限 chmod

    "chmod"命令中的"模式"是用数字表示的三个权限组合,分别表示文件所有者、所在组的用户和其他用户对该文件的读、写和执行权限。其中,读权限用4表示,写权限用2表示,执行权限用1表示,不具备权限用0表示。这三个数字分别相加就是这个文件或目录的权限值,例如755表示文件所有者具有读、写、执行权限,所在组的用户和其他用户具有读、执行权限。

    常用的"chmod"命令示例:

    • 修改文件所有者的读、写、执行权限:chmod 700 file.txt
    • 修改文件所有者和所在组的用户的读、写、执行权限,其他用户只有读和执行权限:chmod 755 file.txt
    • 修改目录及其子目录下的所有文件的权限:chmod -R 755 directory
    • 显示修改的详细信息:chmod -v 700 file.txt

1.11 进程有关命令

  • ps:它显示关于系统上正在运行的活动进程的信息
    • ps -e: 显示所有进程信息。
    • ps -f: 显示进程详细信息。
    • ps -u <username>: 显示指定用户名下的进程信息。
    • ps -aux: 显示所有进程信息,包括系统进程,以及显示更详细的资源使用情况。
    • ps -p <pid>: 显示指定 PID 进程的信息。
  • pstree [options] [pid]:用于以树形结构显示进程之间的关系
    • -p: 显示进程的 PID。
    • -u: 显示进程的所有者。
    • -n: 按照进程 ID 的大小进行排序。
    • -h: 高亮显示当前进程。
    • -a: 显示进程的命令行参数。
  • jobs:显示当前终端下所有正在运行的作业(即后台进程)的列表,以及它们的作业号(job ID)
  • fg:将后台进程切换到前台,并将其设为当前进程。如果指定了作业号,则将该作业切换到前台
  • bg:将当前正在运行的进程放到后台运行,继续执行其他命令。如果指定了作业号,则将该作业放到后台运行
  • <ctrl-z>:将当前正在运行的进程挂起,并将其放到后台运行。可以使用 fg 命令将其切换回前台。
  • kill [options] pid [...]:用于终止(或发送信号给)进程的命令
    • options 是可选参数,pid 是指定的进程 ID,可以同时指定多个进程 ID。如果未指定信号,则默认发送 TERM 信号。常用的 kill 命令选项包括:
      • -s signal: 指定要发送的信号,如 KILLSTOPCONT 等。
      • -l: 列出所有可用的信号列表。
      • 如果要强制结束该进程,则可以使用 -9 选项指定 KILL 信号
  • nohup command [args...]:用于在后台运行命令,且不受用户退出或终端关闭的影响
    • 当执行 nohup 命令时,它会将标准输出和标准错误输出重定向到一个名为 nohup.out 的文件中,该文件位于当前用户的主目录下。这样,即使用户退出终端或关闭终端窗口,被启动的命令仍然可以在后台继续运行,而不会受到影响。
  • nice [-n priority] command [args...]:用于启动一个进程并设置其优先级,使得该进程在竞争 CPU 时间时能够获得更高的优先级
    • priority 表示进程的优先级,取值范围为 -2019,数值越小表示优先级越高,commandargs 表示要执行的命令及其参数。如果未指定优先级,则默认为 10
  • renice [-n priority] pid [...]:用于修改已经在运行的进程的优先级
    • priority 表示要设置的进程优先级,pid 表示要修改优先级的进程 ID。如果未指定优先级,则默认为 10
  • top:一个常用的系统监控工具,可以实时查看系统中进程的 CPU、内存、IO 等使用情况,并按需排序
    • 在终端中输入 top 命令后,会打开一个交互式界面,显示系统的总体情况以及各个进程的使用情况。界面中包括以下信息:
      • top 的运行时间
      • 系统的负载平均值(1 分钟、5 分钟、15 分钟)
      • 系统的总体 CPU 使用情况
      • 物理内存的总量、使用量和空闲量
      • 交换空间的总量、使用量和空闲量
      • 每个进程的进程 ID、用户名、CPU 使用率、内存使用率、进程状态、启动时间等信息

1.12 层次图

2. Ch2 Shell Programming

2.1 基本命令

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UWRu9qm7-1681785542925)(C:\Users\94327\AppData\Roaming\Typora\typora-user-images\image-20230408101539856.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VWDAyQd8-1681785542925)(C:\Users\94327\AppData\Roaming\Typora\typora-user-images\image-20230408101545670.png)]

dirvdirmknodmkfifolocatemaninfo不考

  • chown [OPTIONS] NEW_OWNER FILE(s):用于更改文件或目录的所有权的命令
    • -R:递归更改文件或目录及其子目录的所有权。
    • -v:显示命令执行过程中的详细信息。
    • -c:仅在更改了文件或目录所有权时显示信息。
  • chgrp [OPTIONS] NEW_GROUP FILE(s):用于更改文件或目录的所属组的命令
  • touch [OPTION]... FILE...
    • -a:只更改访问时间戳。
    • -m:只更改修改时间戳。
    • -c:如果文件不存在,则不创建文件。
    • -r FILE:将新文件的时间戳设置为现有文件FILE的时间戳。
  • find:查找文件和目录的常用命令
    • -name:根据文件名搜索文件,支持使用通配符,例如 -name "*.txt"
    • -type:根据文件类型搜索,常见类型包括 f(普通文件)、d(目录)、l(符号链接)等。
    • -size:根据文件大小搜索,支持使用 +- 来表示大于或小于某个大小,例如 -size +10M 表示文件大小大于 10MB。
    • -mtime:根据文件修改时间搜索,例如 -mtime +7 表示文件修改时间在 7 天之前。
    • -perm:根据文件权限搜索,例如 -perm 644 表示文件权限为 644。
    • -exec:对搜索到的文件执行某个命令,例如 -exec rm {} \; 表示删除搜索到的文件。
  • grep [options] pattern [file...]:用于在文本文件中搜索指定的模式,并输出包含该模式的行
    • -i:忽略大小写
    • -r:递归搜索指定目录下的所有文件
    • -w:仅匹配整个单词,而不是单词的一部分
    • -v:仅显示不包含匹配模式的行
    • -n:显示匹配行的行号
    • -c:仅显示匹配的行数
  • su username:用于切换到其他用户账户或超级用户账户
    • 默认情况下,su命令将切换到超级用户账户(root账户),并要求输入超级用户的密码。
    • -c:指定要执行的命令。例如:su -c "ls -l" username表示以username用户身份执行ls -l命令。
    • -l-:切换到目标用户账户,并启动一个新的shell。例如:su - username表示切换到username账户,并启动一个新的shell。
    • -s:指定要使用的shell。例如:su -s /bin/bash username表示使用Bash shell,并以username用户身份登录。

2.2 重定向,会带着考管道

在Linux和Unix操作系统中,重定向是一种常用的命令行技术,用于将命令的输入和输出重定向到文件或其他设备上。

重定向使用特殊的符号来实现,其中最常见的符号包括:

  • >:将命令的输出重定向到文件中,会覆盖文件原有的内容。例如,ls > file.txt表示将ls命令的输出重定向到file.txt文件中。
  • >>:将命令的输出重定向到文件中,会追加到文件末尾。例如,echo "Hello" >> file.txt表示将"Hello"字符串追加到file.txt文件的末尾。
  • <:将文件的内容作为命令的输入。例如,sort < file.txt表示将file.txt文件的内容作为sort命令的输入。
  • |:将一个命令的输出作为另一个命令的输入。例如,ls | grep "txt"表示将ls命令的输出作为grep "txt"命令的输入,以查找文件名中包含"txt"字符串的文件。
  • 2>用于将标准错误输出重定向到指定文件或设备的命令行重定向符号。例如,command 2> error.log会将command命令的标准错误输出重定向到error.log文件中。

需要注意的是,重定向符号的左侧通常是一个命令或一个程序,右侧是要重定向的目标文件、设备或命令。如果目标文件不存在,会自动创建一个新文件。如果目标文件已经存在,则默认情况下会覆盖原有的内容。

重定向技术可以用于各种场景,例如:

  • 将命令的输出保存到文件中,以便后续查看或处理。
  • 将命令的输出传递给其他程序进行处理,以实现多个命令的组合。
  • 将命令的输出发送到网络或其他设备上,以实现实时监控和日志记录等功能。

p9Crji9.png

  • kill -HUP 1234 > killout.txt 2> killerr.txt

    • 这个命令会向进程ID为1234的进程发送HUP(Hang Up)信号,并将标准输出重定向到文件"killout.txt",将标准错误输出重定向到文件"killerr.txt"。

      HUP信号通常用于通知进程重新加载其配置文件。当进程收到HUP信号时,它会关闭和重新打开任何日志文件,重新读取其配置文件,并执行其他必要的操作以根据新配置更新其状态。

  • kill –HUP 1234 > killout.txt 2>& 1

    • 这个命令会向进程ID为1234的进程发送HUP(Hang Up)信号,并将标准输出和标准错误输出合并后重定向到文件"killout.txt"。

      "2>&1"表示将标准错误输出重定向到与标准输出相同的位置。这意味着标准输出和标准错误输出都将被重定向到"killout.txt"文件中。

      在命令行中,每个文件描述符都有一个对应的数字。标准输出的文件描述符为1,标准错误输出的文件描述符为2。">“符号用于输出重定向,”&"符号用于表示将一个文件描述符与另一个文件描述符进行关联。因此,"2>&1"表示将标准错误输出(2)关联到标准输出(1)所指向的文件位置。

p9CrxR1.png

在Linux中,管道(Pipe)是一种将一个进程的输出连接到另一个进程的输入的机制。管道由竖线符号(|)表示。

当在命令行中使用管道时,一个命令的输出将成为另一个命令的输入。例如,如果要查找一个文件中包含特定字符串的行,可以使用"grep"命令,如下所示:

cat file.txt | grep "search_string"

这个命令将文件"file.txt"中的内容传递给"grep"命令,"grep"命令会在这些内容中查找包含"search_string"的行。

使用管道可以将多个命令连接起来,以便实现更复杂的操作。例如,以下命令将会列出当前目录中的所有文件,然后对它们进行按文件大小排序,最后输出最大的10个文件:

ls -l | sort -n -k 5 | tail -n 10

在这个例子中,"ls"命令的输出被连接到"sort"命令的输入,然后"sort"命令的输出被连接到"tail"命令的输入。通过使用管道,我们可以将多个命令组合在一起,以实现更高级的功能。

  • ls | wc –l

    • "ls"命令列出了当前目录中的文件和目录,将它们的输出传递给"wc -l"命令,"wc -l"命令统计并输出这些文件和目录的总行数。
  • ls –lF | grep ^d

    • ls -lF:这个命令会列出当前目录下所有文件和目录的详细信息,其中 -l 表示使用长格式输出,-F 表示在文件名后面加上一个字符来表示其类型(例如,目录名后面加上 /)。
    • grep ^d:这个命令会在 ls -lF 命令的输出结果中查找以字母 “d” 开头的行,也就是说,只会匹配目录。^ 符号表示只匹配以 “d” 开头的行。
  • ar t /usr/lib/libc.a | grep printf | pr -4 -t

    • ar t /usr/lib/libc.a:该命令用于查看名为"/usr/lib/libc.a"的静态库文件中包含的目标文件列表。静态库是一组目标文件的集合,可以在编译时链接到可执行文件中。"ar t"命令用于查看静态库中的目标文件列表。
    • grep printf:该命令用于在先前命令的输出中搜索包含"printf"字符串的行。
    • pr -4 -t:该命令用于将先前命令的输出进行格式化,并以四列的方式进行打印。“-4"选项告诉"pr"命令将输出分成四列,”-t"选项告诉"pr"命令在每个页面的顶部打印标题。

    因此,这个命令的完整意义是,查看名为"/usr/lib/libc.a"的静态库文件中包含的目标文件列表,搜索包含"printf"字符串的行,将结果按照四列的方式格式化打印出来。这个命令的输出将列出静态库文件中包含"printf"字符串的目标文件,并将它们分成四列显示,方便查看。

2.3 环境变量

在Linux中,环境变量是用于存储操作系统和应用程序使用的配置信息的一种机制。以下是关于Linux环境变量的一些基本信息:

  1. 环境变量是存储在操作系统中的一个键值对,其中键表示变量的名称,而值表示变量的值。
  2. 在Linux中,可以通过命令行来设置环境变量,如:export VARIABLE_NAME=value。这将在当前终端中设置变量。
  3. 可以通过编辑特定文件来设置全局环境变量,如:/etc/environment。这将在整个操作系统中设置变量。
  4. 可以通过运行脚本来设置环境变量,例如,在bash中可以编写一个脚本来设置需要的变量,然后在需要时运行该脚本。
  5. 环境变量可用于在操作系统中传递信息,例如,$PATH环境变量用于指定要在哪里查找可执行文件。
  6. 可以使用“echo”命令来显示环境变量的值,如:echo $VARIABLE_NAME。
  7. 可以使用“unset”命令来删除环境变量,例如:unset VARIABLE_NAME。

总之,环境变量是一种非常有用的机制,它们可以帮助您管理Linux系统中的各种设置和配置。


2.4 Shell编程

不超过20分

只考bash,脚本有三种方法执行、用户变量环境变量、参数变量要考、read命令、if语句、字符串比较、和文件相关的条件测试、逻辑操作、case语句(相当于switch命令)、整数运算加($)否则看成字符串运算、select语句、shell脚本没有类型默认全是字符串

2.4.1 编写脚本文件
  1. 脚本文件
    1. 注释
    2. 退出码(exit code)
#!/bin/bash
# Here is comments
for file in *; do
  if grep –l POSIX $file; then
    more $file
  fi
done
exit 0
2.4.2 脚本的三种执行方法:
  • sh script_filebash script_file

    • 利用bash(sh)来执行脚本
  • chmod +x script_file (chown, chgrp optionally) :赋予执行权限

    ./script_file

    • 工作目录执行,指的是执行脚本时,先进入到脚本所在的目录(此时,称为工作目录),然后使用 ./脚本方式执行

    • # 绝对路径执行
      [tan@tan scripts]$ pwd
      /home/tan/scripts
      [tan@tan scripts]$ `pwd`/test.sh
      Hello Shell
      [tan@tan scripts]$ /home/tan/scripts/test.sh
      Hello Shell
      
  • source script_file, or

    . script_file

    • shell环境执行,指的是在当前的shell环境中执行,可以使用 . 接脚本 或 source 接脚本

2.4.3 变量

用户变量:用户在shell脚本里定义的变量

  • 只能使用数字、字母及下划线,且不能以数字开头。

  • 变量的赋值和使用

    var=value 	# 定义变量
    echo $var	# 查看变量值
    
  • read 命令

    • 用法:read var 或 read
    • REPLY variable
  • 赋值时使用的引号

    • 双引号" ":允许通过$符号引用其他变量值
    • 单引号' ':禁止引用其他变量值,$视为普通字符,
    • 反撇号 ` `:命令替换,提取命令执行后的输出结果与$( )效果相同
    • {}可以分隔变量值
    • 定义变量时中间有特殊字符时 比如空格 用单引号或者双引号括起来

    pp7carV.png

环境变量

  • 环境变量:Shell环境提供的变量。通常使用大写字母做名字
环境变量说明
$HOME当前用户的登陆目录
$PATH以冒号分隔的用来搜索命令的目录清单
$PS1命令行提示符,通常是”$”字符
$PS2辅助提示符,用来提示后续输入,通常是”>”字符
$IFS输入区分隔符。当shell读取输入数据时会把一组字符看成是单词之间的分隔符,通常是空格、制表符、换行符等。
  • env命令和set命令的区别是,set命令可以查看所有变量,而env命令只能查看环境变量。
  • 和用户定义变量一样,用unset命令删除变量。

参数变量和内部变量

  • 调用脚本程序时如果带有参数,对应的参数和额外产生的一些变量。
环境变量说明
$#获取当前执行的shell脚本后面接的参数的总个数
$0获取当前执行的shell脚本的文件名,如果执行脚本包含了路径,那么就包括脚本路径
$1, $2, …获取当前执行的shell脚本的第n个参数,n=1…9,当n为0时表示脚本的文件名;如果n大于9,则用大括号括起来;比如${10},接的参数以空格隔开
$*获取当前shell脚本所有传参的参数,不加引号和$@相同;如果给$*加上双引号,如"$*",则表示把所有的参数视为单个字符串,相当于"$1 $2 $3"
$@获取当前shell脚本所有传参的参数,不加引号和$*相同;加上双引号,如"$@",则表示将所有的参数视为不同的独立字符串,相当于"$1" "$2" "$3" "..." 这是将多参数传递给其他程序的最佳方式,因为它会保留所有的内嵌在每个参数里的任何空白。

2.4.4 Read使用

read 内部命令被用来从标准输入读取单行数据。这个命令可以用来读取键盘输入,当使用重定向的时候,可以读取文件中的一行数据。

read [-ers] [-a aname] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]

  • -a 后跟一个变量,该变量会被认为是个数组,然后给其赋值,默认是以空格为分割符。
  • -d 后面跟一个标志符,其实只有其后的第一个字符有用,作为结束的标志。
  • -p 后面跟提示信息,即在输入前打印提示信息。
  • -e 在输入的时候可以使用命令补全功能。
  • -n 后跟一个数字,定义输入文本的长度,很实用。当输入的字符数目达到预定数目时,自动退出,并将输入的数据赋值给变量。
  • -r 屏蔽\,如果没有该选项,则\作为一个转义字符,有的话 \就是个正常的字符了。
  • -s 安静模式,在输入字符时不再屏幕上显示,例如login时输入密码。
  • -t 后面跟秒数,定义输入字符的等待时间。计时满时,read命令返回一个非零退出状态。
  • -u 后面跟fd,从文件描述符中读入,该文件描述符可以是exec新开启的。
#! /bin/bash
echo -n "Enter your name: "       # 参数-n的作用是不换行,echo默认是换行
read name                         #从键盘输入
echo "hello $name, welcome to my program"
exit 0                            #退出shell程序。
read -p "Enter your name:" name   #-p参数,允许在read命令行中直接指定一个提示

read -p "Enter a number:" number
echo $number
exit 0
#! /bin/bash
# 5s内输入
if read -t 5 -p "please enter your name:" name
then
  echo "hello $name, welcome to my script"
else
  echo "sorry, too slow"
fi
exit 0
#! /bin/bash
# 只读取一个字符
read -n1 -p "DO you want to continue[ Y/N] ?" answer
case $answer in
Y|y)
  echo "fine, continue";;
N|n)
  echo "ok, good bye";;
*)
  echo "error choice";;
esac
exit 0
#! /bin/bash
# 不显示输入
read -s -p "Enter your password: " pass
echo "your password is $pass"
exit 0
#! /bin/bash
# 读取文件
count=1	# 赋值语句,不加空格
cat viewFile.sh| while read line	# cat 命令的输出作为read命令的输入,read读到>的值放在line中
do
  echo "Scount:$line"
  count=$(($count + 1))
done
echo "Total Count:$count"
exit 0
2.4.5 与文件有关的条件测试

pp7TKAI.png

  • -a/-e [文件]:文件是否存在
  • -d [文件]:文件存在且为目录则为真,即测试表达式成立
  • -f [文件]:文件存在且为普通文件则为真,即测试表达式成立
  • -s [文件]:文件存在且文件大小不为 0 则为真
  • -r [文件]:文件存在且可读为真
  • -w [文件]:文件存在且可写为真
  • -x [文件]:文件存在且可执行则为真
2.4.6 字符串比较
字符串比较结果
str1=str2两个字符串相同则结果为真
str1!=str2两个字符串不相同则结果为真
-z str字符串为空则结果为真
-n str字符串不为空则结果为真
2.4.7 算术比较
算术比较结果
expr1 –eq expr2 两个表达式相等则结果为真
expr1 –ne expr2两个表达式不等则结果为真
expr1 –gt expr2expr1 大于 expr2 则结果为真
expr1 –ge expr2expr1 大于或等于 expr2 则结果为真
expr1 –lt expr2 expr1 小于 expr2 则结果为真
expr1 –le expr2 expr1 小于或等于 expr2 则结果为真
2.4.8 逻辑操作
逻辑操作结果
!expr逻辑表达式求反
expr1 -a expr2两个逻辑表达式“And”(“与”)
expr1 -o expr2两个逻辑表达式“Or”(“或”)
2.4.9 条件语句

if语句

  • 形式

    if [ expression ]
    then
    	statements
    elif [ expression ]
    then
    	statements
    elifelse
    	statements
    fi
    
  • 紧凑形式

    • ; (同一行上多个命令的分隔符)
# 例1.(.bash_profile文件中)
if [ -f ~/.bashrc ]; then
	. ~/.bashrc
fi

# 例2
#!/bin/sh
echo “Is this morning? Please answer yes or no.”
read answer
if [$answer= “yes” ]; then
	echo “Good morning”
elif [$answer= “no” ]; then
	echo “Good afternoon”
else 
	echo “Sorry, $answer not recognized. Enter yes or no”
	exit 1
fi
exit 0

case语句

  • 形式

    case str in
    str1 | str2) statements;;
    str3 | str4) statements;;
    *) statements;;
    esac
    
#!/bin/sh
echo “Is this morning? Please answer yes or no.”
read answer
case$answerin
	yes | y | Yes | YES) echo “Good morning!;;
	no | n | No | NO) echo “Good afternoon!;;
	*) echo “Sorry, answer not recognized.” ;;
esac
exit 0
2.4.10 重复语句

for语句

  • 形式

    for var in list
    do
    	statements
    done
    
  • 适用于对一系列字符串循环处理

#!/bin/sh
for file in $(ls f*.sh); do
lpr $file
done
exit 0

while语句

  • 形式

    while condition
    do
    	statements
    done
    
quit=n
while [$quit!= “y” ]; do
	read menu_choice
	case$menu_choicein
		a) do_something;;
		b) do_anotherthing;;
		…
		q|Q) quit=y;;
		*) echo “Sorry, choice not recognized.”;;
	esac
done

until语句

  • 形式

    until condition
    do
    	statements
    done
    
  • Not recommended (while statement is preferred)

select语句

  • 形式

    select item in itemlist
    do
    	statements
    done
    
  • 作用

    • 生成菜单列表
# 例(一个简单的菜单选择程序)
#!/bin/sh
clear
select item in Continue Finish
do
case$itemin
Continue) ;;
Finish) break ;;
*) echo “Wrong choice! Please select again!;;
esac
done
2.4.11 命令表和语句块
pp7H9W6.png[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mNDiunPc-1681785542927)(C:\Users\94327\AppData\Roaming\Typora\typora-user-images\image-20230408162712387.png)]
2.4.12 函数
pp7HiQO.pngpp7HFyD.png
# 调用上述例子中的函数 yesno
if yesno “Continue installation? [n]1 ; then
	:		# `:` 为空命令
else
	exit 1
fi
2.4.13 杂项命令
pp7HVwd.pngpp7HufP.png
2.4.14 算术扩展
  • $((...))扩展

    #!/bin/sh
    x=0
    
    while [$x” –ne 10 ]; do
    	echo $x
    	x=$(($x+1))
    done
    
    exit 0
    
    [root@zxp1 ~]# echo $((3+2))
    5
    [root@zxp1 ~]# echo $((3*2))
    6
    [root@zxp1 ~]# echo `expr 2+3`   //运算符前后需要空格
    2+3
    [root@zxp1 ~]# echo `expr 2 + 3` 
    5
    [root@zxp1 ~]# echo `expr 2 * 3` //会提示语法错误,需要转义
    expr: syntax error
    [root@zxp1 ~]# echo `expr 2 \* 3`
    6
    
2.4.15 参数扩展
  • 问题:批处理 1_tmp, 2_tmp, …

  • 方法

    #!/bin/sh
    i=1
    while [$i” –ne 10 ]; do
    	touch${i}_tmp”
    	i=$(($i+1))
    done
    exit 0
    
    Parameter ExpansionDescription
    $(param:-default)如果param为空,就把它设置为default的值
    ${#param}给出param的长度
    ${param%word}从param的尾部开始删除与word匹配的最小部分,然后返回剩余部分
    ${param%%word}从param的尾部开始删除与word匹配的最长部分,然后返回剩余部分
    ${param#word}从param的头部开始删除与word匹配的最小部分,然后返回剩余部分
    ${param##word}从param的头部开始删除与word匹配的最长部分,然后返回剩余部分
2.4.16 即时文档
  • 在shell脚本中向一条命令传送输入数据

    #!/bin/bash
    cat >> file.txt << !CATINPUT!
    Hello, this is a here document.
    !CATINPUT!
    

    这是一个 Bash 脚本的示例,它将一段文本附加到 file.txt 文件中。具体来说,它使用了 Here Document 的语法结构,这是一种将多行文本传递给命令或程序的方法,可以避免手动输入或编辑多行文本。

    在这个例子中,cat 命令用于显示和操作文件的内容,>> 操作符用于将输出追加到文件的末尾,file.txt 是要被附加的目标文件。然后,<< 操作符用于指示这是一个 Here Document,!CATINPUT! 是一个标识符,它告诉 Shell 要读取 Here Document 的内容直到遇到另一个相同的标识符。

    在这个例子中,Here Document 中包含一行文本 Hello, this is a here document.,当 Shell 遇到 Here Document 的结束标识符时,它将把这行文本追加到 file.txt 文件的末尾,然后退出 Here Document 的输入模式。

3. Ch3-0 Programming prerequisite

3.1 ELF

​ ELF代表“可执行和可链接格式”(Executable and Linkable Format),是在类Unix操作系统中用于可执行文件、目标代码、共享库和核心转储的标准文件格式。ELF的设计目的是灵活、可扩展和跨平台的,可以实现高效的执行和简单的链接。

​ windows下可执行文件的封装格式: MZ
​ linux下的可执行文件封装格式: ELF,封装一般发生在链接过程中


3.2 程序设计语言:解释型和编译型

​ 解释型程序设计语言是指在运行时逐行解释代码,并在每次执行代码时动态地进行类型检查和运行时错误检查。这种语言不需要显式的编译步骤,而是通过解释器在运行时逐行解释执行代码。由于每次执行代码时都需要进行解释和检查,因此解释型语言通常比编译型语言执行速度慢。

​ 编译型程序设计语言是指在运行前需要先将源代码编译成可执行文件的过程。编译过程将源代码转换成计算机能够理解的二进制代码,这种代码可以直接在目标机器上运行。由于编译器在编译过程中可以对代码进行优化,因此编译型语言通常比解释型语言执行速度快。

​ 常见的解释型语言包括Python、JavaScript和Ruby等,而常见的编译型语言包括C、C++和Java等。不过,实际上很多语言也有两种不同的实现方式:解释器和编译器。例如,Python既有解释器又有编译器,可以将Python代码编译成字节码,以提高执行效率。


3.3 编译过程

在Linux中,C程序的编译过程一般包括以下步骤:

  1. 编写C源代码文件(通常以.c为后缀),使用文本编辑器编写C源代码文件,例如使用vi、nano等编辑器。

  2. 预处理(Preprocessing):使用预处理器(通常是gcc -E命令)对源代码进行预处理,例如展开#include头文件、宏替换、条件编译等,生成.i文件。

    gcc -E main.c -o main.i
    
  3. 编译(Compilation):使用编译器(通常是gcc命令)将预处理后的代码编译成汇编代码(通常是以.s为后缀),进行语法和语义检查,生成目标文件(通常是以.o为后缀)。

    gcc -c main.s -o main.o
    
  4. 链接(Linking):使用链接器(通常是ld命令)将目标文件和库文件链接成可执行文件(通常是以.out或者没有后缀名为后缀),解析符号,生成可执行文件。

    gcc main.o -o main.out
    

在上述过程中,也可以将预处理、编译、链接三个步骤合并为一个命令,例如:

gcc main.c -o main.out

这个命令会自动进行预处理、编译、链接三个步骤,生成可执行文件。除了使用gcc命令之外,也可以使用其他C编译器,例如clang、tcc等。

问:编译时头文件和#include的处理?

在编译时,头文件和#include的处理主要是由预处理器完成的。预处理器会将#include指令所引用的头文件包含到源代码文件中,然后对包含后的文件进行宏替换、条件编译等操作,最后将处理后的代码发送给编译器进行编译。

问:为什么要做链接?(link)

在编写C程序时,通常需要使用不同的源文件,这些源文件中可能会包含一些函数和变量等符号,这些符号需要在编译和链接时进行解析和处理。链接的主要作用就是将各个目标文件和库文件中的符号进行解析和合并,生成可执行文件。

问:静态库与动态库

  • 静态库

    • 静态库是一组已经编译好的二进制目标文件的集合,其中包含了一些函数、变量等可重用的代码模块。当使用静态库时,链接器会将所有需要的代码模块从静态库中提取出来,与应用程序的代码一起链接生成一个独立的可执行文件。这意味着,所有的代码都被包含在了可执行文件中,程序在运行时不需要依赖任何外部的库文件。
    • 静态库的优点是使用简单,不需要额外的依赖关系,能够确保程序的可移植性和稳定性。缺点是静态库文件比较大,占用的内存空间相对较多,而且更新和维护比较困难。
  • 动态库

    • 动态库是一些被编译成二进制目标文件的代码模块,可以在程序运行时动态地加载到内存中,并被多个进程共享。当一个应用程序需要调用动态库中的某个函数或变量时,系统会在动态库中查找对应的符号,如果找到就直接使用,否则就报错。
    • 动态库的优点是可以动态加载,多个应用程序可以共享同一个动态库,从而减少内存的占用。另外,动态库的更新和维护也相对简单。缺点是需要运行时动态链接,可能会影响程序的性能;同时,如果动态库本身存在问题,会影响多个应用程序的正常运行。

3.4 gcc

  • gcc -c (编译)

  • gcc (链接 或者 编译 + 链接)

  • g++ (C++对应的命令,其实就是换了前端)

  • gcc [options] [filename]

    • -E: 只对源程序进行预处理(调用cpp预处理器)
    • -S: 只对源程序进行预处理、编译
    • -c: 执行预处理、编译、汇编而不链接
    • -o output_file: 指定输出文件名
    • -g: 产生调试工具必需的符号信息
    • -O/On: 在程序编译、链接过程中进行优化处理
    • -Wall: 显示所有的警告信息
    • -Idir: 指定额外的头文件搜索路径
    • -Ldir: 指定额外的库文件搜索路径
    • -lname: 链接时搜索指定的库文件
    • -DMACRO[=DEFN]: 定义MACRO宏(针对#define)
  • 编译后调试一般在一台机器上,而不会在多台机器

  • 补充:

    1. 调试的时候仍然使用的是本地编译好的二进制文件
    2. 编译的时候没开优化,源代码的语句编译成的汇编码是多条语句,是一对多的关系
    3. 调试器:在执行编译后的二进制码,二进制码会被打标签,记录哪一个源代码的哪一行编译而来的。
    4. -g参数:告诉编译器,每一个编译完的二进制码上打上文件名和行号的标签
    5. 编译完之后,用其他的机器调试可能是不行的,因为file的路径一般是不一样的。
    6. -O优化,二进制码打乱,不优化的话,源代码和汇编代码是对应着的;一些无关的操作会被编译器扔掉;会把源代码和汇编码之间一对多的关系破坏掉
  • 在不改变源代码的基础上,在文件中添加#define预处理指令。

    gcc -DAA=2
    # 就相当于在源码中添加了#define AA 2
    
  • 链接器在链接的时候如何找到库文件?

    • 环境变量LD_LIBRARY_PATH指定的路径
    • 默认库文件路径
    • 静态库
  • 编译器不需要额外指定头文件的文件名(因为源码中有头文件名)

    -lm
    # 库文件名为libm.a
    

3.5 常见拓展名

  • .c:C语言源文件,包含C程序的源代码。
  • .i:经过预处理后的C语言源代码文件。
  • .cc .cp .C .cpp:C++语言源文件,包含C++程序的源代码。
  • .ii:经过预处理后的C++语言源代码文件。
  • .h:C或C++头文件。
  • .H .hh:C++头文件。
  • .s:汇编语言源代码文件。
  • .S:经过预处理后的汇编语言源代码文件。
  • .o:目标文件,是编译器将源代码编译后生成的中间文件,包含机器代码和一些符号信息。
  • .a:静态库文件,也称为归档文件,是一组目标文件的集合,经过归档打包后生成的库文件,包含一些函数和数据,可以被静态链接到可执行文件中。
  • .h:头文件,包含程序中的函数声明和一些宏定义等信息,通常被用于多个源文件之间共享代码。
  • .so:共享库文件,也称为动态库文件,是一种特殊的共享对象文件,包含一些函数和数据,可以在运行时动态加载,被多个程序共享使用。

这些文件类型是在编译和链接过程中经常使用的。通常,C和C++源代码(.c、.cpp)需要被编译成目标文件(.o),然后将目标文件和库文件(.a、.so)链接生成可执行文件,而头文件(.h)则可以被多个源文件共享使用。


3.6 gdb主观题:作为一个调试器需要实现什么功能、调试器的原理

  • 作为一个调试器,需要实现以下功能:

    • 启动和停止被调试程序。
    • 单步执行程序,以便逐行或逐语句执行程序。
    • 暂停程序的执行,以便检查当前状态和变量的值。
    • 设置和删除断点,以便在程序执行到指定行或指定条件时停止执行。
    • 查看和修改变量和内存的值。
    • 检查和修改寄存器的值。
    • 跟踪函数调用和返回,以便调试函数的参数和返回值。
    • 执行表达式并显示结果,以便计算变量或表达式的值。
    • 监控程序的输出和错误信息。
  • 调试器的原理通常包括以下步骤:

    • 调试器启动被调试程序,并与之进行通信。
    • 调试器通过操作系统提供的API来获取程序的调试信息,如进程状态、寄存器值、内存地址、线程信息等。
    • 调试器通过与操作系统内核的交互,设置断点和访问被调试程序的内存。
    • 当程序执行到断点处时,调试器会停止程序的执行,并将控制权交给调试器。调试器可以显示程序的状态和变量值,以便程序员进行调试。
    • 程序员可以通过调试器来单步执行程序、查看和修改变量值、设置和删除断点等操作。
    • 当调试完成后,程序员可以选择继续程序的执行或者终止程序的执行。如果程序已经结束,调试器会关闭被调试程序并退出。

​ 总的来说,调试器的原理就是通过与操作系统内核的交互,监控和控制被调试程序的执行,以便程序员进行调试和错误修复。


3.7 makefile可能会跟编程题一起考(eg:给一个程序写一个makefile)

makefile:

  • 定义整个工程的编译规则

    • 一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作 。
  • 自动化编译

    • 只需要一个make命令,整个工程完全自动编译 ;make是一个命令工具,是一个解释makefile中指令的命令工具;
  • Makefile是用于自动编译和链接的,一个工程有很多文件组成,每一个文件的改变都会导致工程的重新链接,但是不是所有的文件都需要重新编译,Makefile中记录有文件的信息,在make时会决定在链接的时候需要重新编译哪些文件。

  • make命令格式:make [-f Makefile] [option] [target]

  • Makefile执行次序:

    • make会在当前目录下找名字叫“Makefile” 或“makefile” 的文件。
    • 查找文件中的第一个目标文件(target),举例中的hello
    • 如果hello文件不存在,或是hello所依赖的文件修改时间要比hello新,就会执行后面所定义的命令来生成hello文件。
    • 如果hello所依赖的.o文件不存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。(类似一个堆栈的过程)
    • make根据.o文件的规则生成 .o 文件,然后再用 .o 文件生成hello文件。
  • clean: rm *.o hello

    • “伪目标”并不是一个文件,只是一个标签,所以make无法生成它的依赖关系和决定它是否要执行,只

      能通过显示地指明这个“目标”才能让其生效

    • “伪目标”的取名不能和文件名重名

    • 为了避免和文件重名的这种情况,可以使用一个特殊的标记“.PHONY”来显示地指明一个目标是“伪目标”,向make说明,不管是否有这个文件,这个目标就是“伪目标”

    • 伪目标一般没有依赖的文件,但也可以为伪目标指定所依赖的文件。

    • 伪目标同样可以作为“默认目标”,只要将其放在第一个。

  • 多目标:

    • 当多个目标同时依赖于一个文件,并且其生成的命令大体类似,可以使用一个自动化变量“$@”表示着目前规则中所有的目标的集合

      bigoutput littleoutput : text.g
      generate text.g -$(subst output,,$@) > $@
      
      上述规则等价于
      bigoutput : text.g
      generate text.g -big > bigoutput
      littleoutput : text.g
      generate text.g -little > littleoutput
      
ppHPle1.png
- TOPDIR = ../:将 TOPDIR 设置为上级目录。
- include $(TOPDIR)Rules.mak:从上级目录中的 Rules.mak 文件中导入变量和规则。
- EXTRA_LIBS +=:将 EXTRA_LIBS 变量添加到 Makefile 中的额外库。
- EXEC = $(INSTALL_DIR)/hello:将 EXEC 变量设置为 INSTALL_DIR 目录中的 hello 可执行文件。
- OBJS = hello.o:将 OBJS 变量设置为编译 hello.c 文件生成的目标文件 hello.o。
- all: $(EXEC):设置 all 为默认目标,并将其依赖于 EXEC 变量,以构建 hello 可执行文件。
- $(EXEC): $(OBJS):将 EXEC 变量设置为目标,该目标需要 OBJS 变量中列出的所有目标文件才能生成。
- $(CC) $(LDFLAGS) -o $@ $(OBJS) $(EXTRA_LIBS)::使用 $(CC) 编译器和 $(LDFLAGS) 标志来将 OBJS 变量中列出的目标文件和 EXTRA_LIBS 变量中列出的库文件链接在一起,生成 EXEC 变量中指定的 hello 可执行文件。
- install:将 hello 可执行文件安装到 INSTALL_DIR 目录中。
- $(EXP_INSTALL) $(EXEC) $(INSTALL_DIR):使用 $(EXP_INSTALL) 安装命令来将 EXEC 变量中指定的 hello 可执行文件复制到 INSTALL_DIR 目录中。
- clean: -rm -f $(EXEC) *.elf *.gdb *.o:清除所有生成的目标文件和可执行文件。

3.8 预定义变量

  • $< 第一个依赖文件的名称

  • $? 所有的依赖文件,以空格分开,这些依赖文件的修改日期比目标的创建日期晚

  • $+ 所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件

  • $^ 所有的依赖文件,以空格分开,不包含重复的依赖文件

  • $* 不包括扩展名的目标文件名称

  • $@ 目标的完整名称

  • $% 如果目标是归档成员,则该变量表示目标的归档成员名称

4. Ch3-1 系统编程

4.1 文件系统的三种含义

  • 指一种特定的文件格式。例如,我们说Linux的文件系统时Ext2,MSDOS的文件系统是FAT16,而Windows NT的文件系统是 NTFS 或 FAT32,就是这个意思。
  • 指按特定格式进行了“格式化”的一块存储介质。当我们说“安装”或拆卸一个文件系统时,指的就是这个意思。
  • 指操作系统中(通常在内核中)用来管理文件系统以及对文件进行操作的机制及其实现。

4.2 VFS(VFS模型会在内核创建的四种对象要求掌握)

  • 虚拟; 仅存在于内存中

  • 组件:

    • 超级块(super block):某一个磁盘的某一个分区的文件系统的信息
      • 记录文件系统类型
      • 记录文件系统的参数
    • i节点对象(i-node object):index
      • 记录的是真正的文件,文件存储在磁盘上时是按照索引号访问文件的
    • 文件对象(file object)
      • 记录的是文件描述符,索引号
      • 不对应真正的文件,文件open后会创建出文件对象。
      • 文件没有close,则内核中的文件对象就没有释放
    • 目录对象(dentry object)


4.3 硬连接软连接

  • 硬链接 Hard link
    • 不同的文件名对应同一个inode
    • 不能跨越文件系统
    • 对应系统调用link
  • 软连接
    • 存储被链接文件的文件名(而不是inode)实现链接
    • 可跨越文件系统
    • 对应系统调用symlink

4.4 系统调用和C库的关系

【考试务必注意,如果要求用系统调用但是用了库函数分数扣光】

  • 都以C函数的形式出现
  • 系统调用
    • Linux内核的对外接口; 用户程序和内核之间唯一的接口; 提供最小接口
  • 库函数
    • 依赖于系统调用; 提供较复杂功能
    • 例:标准I/O库

4.5 文件描述符

​ 文件描述符是一个非负整数,用于在操作系统中唯一标识一个打开的文件、设备、网络连接或管道等。Unix和类Unix系统中,文件描述符的范围通常是0到1023(或者更高),其中0、1和2分别保留给标准输入、标准输出和标准错误流

  • 文件描述符

    • 一个小的非负整数:int fd;
    • <unistd.h>
      • STDIN_FILENO(0),STDOUT_FILENO(1),STDERR_FILENO(2)
  • 文件操作的一般步骤:open - read/write - [lseek] - close

4.6 权限

ppHVeW6.pngppHV0mQ.png

4.7 系统调用

4.7.1 系统调用头文件
  • <unistd.h>
  • ``<sys/types.h>`
  • <fcntl.h>
  • ``<sys/stat.h>`
  • <dirent.h>
4.7.2 系统调用
  • 重点 int open(const char *pathname, int flags, mode_t mode),可以没有mode,但是如果flags中有O_CREAT则必须要mode

    • flags
      • O_RDONLY:只读
      • O_WRONLY:只写
      • O_RDWR:读写
      • O_APPEND:追加模式打开
      • O_TRUNC:覆盖模式
      • O_CREAT:文件不存在则创建
      • O_EXCL:和O_CREAT同时使用,存在时出错
      • O_NONBLOCK:非阻塞
    • mode
      • S_IRUSR
      • S_IWUSR
      • S_IXUSR
      • S_IRWXU
      • S_IRGRP
      • S_IWGRP
      • S_IXGRP
      • S_IRWXG
      • S_IROTH
      • S_IWOTH
      • S_IXOTH
      • S_IRWXO
  • off_t lseek(int fildes, off_t offset, int whence)如果成功返回偏移地址,否则为-1

    • SEEK_SET:从头偏移offset
    • SEEK_CUR:从当前偏移offset
    • SEEK_END:从尾偏移offset
  • 重点 int fcntl(int fd, int cmd, struct flock *lock) 返回值;若成功则依赖于cmd,若出错则为-1

    • F_DUPFD:复制文件描述符
    • F_GETFD/F_SETFD:获取/设置文件描述符标志,为解决fork子进程执行其他任务(exec等)导致父进程的文件描述符被复制到子进程中,使得对应文件描述符无法被之后需要的进程获取。设置了这个标记后可以使得子进程在执行exce等命令后释放对应的文件描述符资源。
    • F_GETFL/F_SETFL:获得/设置文件状态标志(open/creat中的flags 参数),目前只能更改0_APPEND , 0_ASYNC, 0_DIRECT, 0_NOATIME,O_NONBLOCK
    • F_GETOWN/F_SETOWN: 管理1/0可用相关的信号。获得或设置当前文件描述符会接受SIGI0和SIGURG信号的进程或进程组编号F_GETLK/F_SETLK/F_SETLKW: 获得/设置文件锁,设置为F_GETLK时需要传入flock* 指针用于存放最后的锁信息。S_SETLK 需要传入flock *指针表示需要改变的锁的内容,如果不能被设置,则立即返回EAGAIN。
    • F_GETLK:获得文件的封锁信息
    • F_SETLK:对文件的某个区域封锁或解封
    • F_SETLKW:功能和F_SETLK,如果锁被占用则等待
  • size_t read(int fd, void *buf, size_t count) 返回值为读到的字节数,如果已经到文件尾为0,若出错为-1

  • size_t write(int fd, const void *buf, size_t count) 返回值为已经成功写的字节数,若出错为-1

  • int close(int fd) 关闭文件描述符,释放资源

  • int stat(const char *filename, struct stat *buf);

    • 把对应文件名的相关信息存到对应地址里
    • filename 文件名
    • 当文件是一个符号链接时,stat返回的是指向的文件的信息
  • int fstat(int filedes, struct stat *buf);

    • 把对应文件描述符的相关信息存储到对应地址
    • fstat系统调用的接受的是一个文件描述符,而其他接受的是文件全路径。
  • int lstat(const char *file_ name, struct stat *buf);Return: 0 if success; -1 if failure):当文件是一个符号链接时,lstat返回的是符号链接本身的信息

4.8 C库函数

4.8.1 C库头文件
  • <stdio.h>
4.8.2 C库函数
  • FILE *fopen(const char * filename, const char* mode);
    • r 读
    • w 清空写
    • a 追加
    • r+ 读写
    • w+ 清空读写
    • a+ 不清空读写
  • FILE *fdopen(int fildes, const char *mode)根据已打开的文件描述符创建一个流
  • int fclose(FILE *stream)
  • int getc(FILE *fp):是预定义宏,无函数副作用,更快
  • int fgetc(FILE *fp):常用,在用到函数副作用/函数指针用
  • int putc(int c, FILE *fp)
  • int fputc(int c, FILE *fp)
  • int fputs(const char *s, FILE * stream);
  • char *fgets(char *s, int size, FILE *stream)常用,最多从流中读取并存储size-1个字符,并最后添加一个\0
  • int fseek(FILE *stream, long int offset, int whence),whence的取值:0是文件首、1是不跳转、2是文件尾向前。
  • long ftell(FILE *stream)当前位置到文件开头位置
  • void rewind(FILE *stream)跳到开头
  • int fflush(FILE *stream)刷新文件流,将流里的数据立刻写入文件
  • int fileno(FILE *fp)确认流使用的底层文件描述符
  • 重点int fprintf(FILE *stream, const char *format, ...);
  • 重点int sprintf(char *str, const char *format, ...);
  • size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
    • fread函数的作用是从文件指针stream所指向的文件中读取nmemb个大小为size字节的数据块,并将其存储到以ptr指向的内存区域中。函数返回成功读取的数据块数量,如果返回值小于nmemb,则可能遇到了文件结束或者读取错误等情况。
  • size fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
    • fwrite函数的作用是将nmemb个大小为size字节的数据块从以ptr指向的内存区域写入到文件指针stream所指向的文件中。函数返回成功写入的数据块数量,如果返回值小于nmemb,则可能遇到了文件写入错误等情况。

编程的时候掌握最长的那个open就行

close需要注意

fcntl的文件锁的部分需要掌握

4.8.3 Reposition a stream
#include <stdio.h>
int fseek(FILE *stream, long int offset, int whence);
long ftell(FILE *stream);
void rewind(FILE *stream);
  • fseek()函数允许你将文件流指针移动到一个指定位置。它的参数stream是指向文件流的指针,offset是要移动的字节数,whence用于指定起始点,可以是SEEK_SET(文件开头),SEEK_CUR(当前位置),或SEEK_END(文件结尾)。如果函数执行成功,它将返回0,否则返回非0值。
  • ftell()函数用于获取当前文件流指针的位置。它的参数stream是指向文件流的指针。如果函数执行成功,它将返回当前指针位置相对于文件开头的字节数,否则返回-1L
  • rewind()函数用于将文件流指针移动到文件开头。它的参数stream是指向文件流的指针。该函数没有返回值。
4.8.4 目录操作

掌握作业内容

  • mkdir/rmdir
  • chdir/fchdir, getcwd
    • chdir()系统调用用于将进程的当前工作目录更改为指定目录。该函数的参数是一个字符串,指定要更改为的目录路径。如果函数执行成功,它将返回0,否则返回-1。
    • fchdir()系统调用是chdir()的一种变体,不过它使用一个文件描述符来指定目录。该函数的参数是一个文件描述符,该描述符指向一个目录的打开文件。如果函数执行成功,它将返回0,否则返回-1。
    • getcwd()系统调用用于获取当前进程的工作目录。它的参数是一个指向存储目录路径的缓冲区的指针,以及缓冲区的大小。如果函数执行成功,它将返回指向缓冲区的指针,否则返回NULL。
  • Read a directory
    • opendir/closedir
      • opendir()函数需要一个目录名作为参数,并返回一个指向目录流的指针。
      • closedir()函数则用于关闭先前由opendir()打开的目录流,并释放与其相关的系统资源。
    • readdir
      • readdir()是C语言中用于读取目录内容的函数。它需要一个指向目录流的指针作为参数,并返回指向一个dirent结构体类型的指针。dirent结构体中包含了文件名和文件类型等信息。
    • telldir
      • telldir()是C语言中用于获取目录流中当前位置的函数。它需要一个指向目录流的指针作为参数,并返回一个long int类型的值,表示当前在目录流中的位置。
    • seekdir
      • “seekdir” 函数的作用是设置目录流中的指针,以指定下一个将被读取的目录项。可实现随机访问。
4.8.5 文件锁
  • 记录锁
  • 劝告锁
    • 检查,加锁有应用程序自己控制
  • 强制锁
    • 检查,加锁由内核控制
    • 影响[open() read() write()]等
  • 共享锁:读锁
  • 排他锁:写锁

临时文件看一下(创建文件过程)

5. Ch4 内核与驱动简介

5.1 内核的概念(写出主要的层次结构中模块)

  • 操作系统是一系列程序的集合,其中最重要的部分构成了内核

  • 单内核/微内核

    • 单内核是一个很大的进程,内部可以分为若干模块,运行时是一个独立的二

      进制文件,模块间通讯通过直接调用函数实现

    • 微内核中大部分内核作为独立的进程在特权下运行,通过消息传递进行通讯

    ppHMtED.png

5.2 驱动和模块

驱动和模块是考试重点:形式、对应的命令、模块依赖的意思

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

加载模块

  • 底层命令
    • insmod:加载模块
    • rmmod:释放模块
  • 高层命令
    • modprobe
    • modprobe -r

模块依赖

定义

  • 一个模块A引用另一个模块B所导出的符号,我们就说模块B被模块A引用。
  • 如果要装载模块A,必须先要装载模块B。否则,模块B所导出的那些符号的引用就不可能被链接到模块A中。这种模块间的相互关系就叫做模块依赖。

模块的依赖

  • 自动按需加载

  • 自动按需卸载

  • moddep

  • lsmod

  • modinfo

模块间的通讯

模块是为了完成某种特定任务而设计的。其功能比较的单一,为了丰富系统的功能,所以模块之间常常进行通信。其之间可以共享变量,数据结构,也可以调用对方提供的功能函数。

模块相关命令

  • insmod <module.ko> [module parameters]

    • Load the module
    • 注意,只有超级用户才能使用这个命令
  • rmmod

    • Unload the module
  • lsmod

    • List all modules loaded into the kernel
    • 这个命令和cat /proc/modules等价
  • modprobe [-r] <module name>

    • Load the module specified and modules it depends

5.4 Linux内核模块和应用程序的区别(4点以上)

C语言程序Linux
运行用户空间内核空间
入口main()module_init()指定;
出口module_exit()指定;
运行直接运行insmod
调试gdbkdbug, kdb, kgdb等

6. HUAWEI-openEuler(15分)

  • 2019年底EulerOS被正式推到开源社区,成为openEuler

  • openEuler是一款通用服务器操作系统

  • 支持x86和ARM等多种处理器架构

  • 鲲鹏处理器基于ARMv8-64指令集开发的通用处理器

  • openEuler

    • 提供一种Numa aware解决方案,提升了多核调度性能
    • 提供鲲鹏加速引擎插件,使能鲲鹏硬件加速能力
    • 提供iSulad轻量级容器全场景解决方案
    • 提供了A-Tune智能优化引擎
  • openEuler支持的通信机制:共享内存消息传递

    • 通信模块:支持gRPC/RESTFUL两种通信方式
  • 内存管理机制

  • 大量使用寄存器

  • 使用经典指令集

  • 没有神经网络加速引擎,而是多核调用技术软硬件协同IsulaA-Tune

  • CPU调度采用使用了多队列调度策略

7. 往年题

Linux重定向的实现机制

Linux重定向的实现机制主要依赖于文件描述符(File Descriptor)和进程间通信(IPC)机制。在Linux中,每个进程都会有三个默认打开的文件描述符:标准输入(stdin,文件描述符为0)、标准输出(stdout,文件描述符为1)和标准错误输出(stderr,文件描述符为2)。

在Linux中,可以使用重定向符号将标准输入、标准输出、标准错误输出重定向到指定的文件或者命令中。具体的重定向符号如下:

  • >:将标准输出重定向到指定文件中,如果文件不存在则会创建文件并写入内容,如果文件已经存在则会清空文件内容并写入新的内容。
  • >>:将标准输出重定向到指定文件中,如果文件不存在则会创建文件并写入内容,如果文件已经存在则会在文件末尾追加新的内容。
  • <:将指定文件中的内容作为标准输入。
  • 2>:将标准错误输出重定向到指定文件中,如果文件不存在则会创建文件并写入内容,如果文件已经存在则会清空文件内容并写入新的内容。
  • 2>>:将标准错误输出重定向到指定文件中,如果文件不存在则会创建文件并写入内容,如果文件已经存在则会在文件末尾追加新的内容。
  • &>>&:将标准输出和标准错误输出都重定向到指定文件中,如果文件不存在则会创建文件并写入内容,如果文件已经存在则会清空文件内容并写入新的内容。

在实现重定向时,Linux系统会使用dup2()系统调用来复制文件描述符,将标准输入、标准输出、标准错误输出重定向到指定文件描述符上,从而实现重定向的功能。

copy.cpp + makefile

#include <iostream>
#include <fcntl.h>
#include <unistd.h>

#define BUFFER_SIZE 1024

int main(int argc, char *argv[]) {
    if (argc < 3) {
        std::cerr << "Usage: " << argv[0] << " <source_file> <destination_file>" << std::endl;
        return 1;
    }

    int source_fd = open(argv[1], O_RDONLY);
    if (source_fd == -1) {
        std::cerr << "Failed to open source file " << argv[1] << std::endl;
        return 1;
    }

    int dest_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (dest_fd == -1) {
        std::cerr << "Failed to create destination file " << argv[2] << std::endl;
        return 1;
    }

    char buffer[BUFFER_SIZE];
    int bytes_read;
    while ((bytes_read = read(source_fd, buffer, BUFFER_SIZE)) > 0) {
        int bytes_written = write(dest_fd, buffer, bytes_read);
        if (bytes_written != bytes_read) {
            std::cerr << "Failed to write to destination file " << argv[2] << std::endl;
            return 1;
        }
    }

    close(source_fd);
    close(dest_fd);

    return 0;
}
CC=g++
CFLAGS=-c -Wall

all: copy

copy: copy.o
    $(CC) copy.o -o copy

copy.o: copy.cpp
    $(CC) $(CFLAGS) copy.cpp

clean:
    rm -rf *.o copy

在上面的 makefile 文件中,我们定义了一个 CC 变量表示使用的编译器,一个 CFLAGS 变量表示编译选项,以及三个目标:

  • all:编译 copy 目标。
  • copy:将 copy.o 文件链接成可执行文件 copy
  • copy.o:编译 copy.cpp 文件并生成目标文件 copy.o

如果要编译 copy.cpp,只需要在终端中进入 makefile 文件所在的目录,然后执行 make 命令即可。执行完毕后,会在当前目录下生成一个名为 copy 的可执行文件。例如,执行以下命令即可编译 copy.cpp

make

如果要清除编译生成的目标文件和可执行文件,可以执行以下命令:

make clean

这样就可以清除编译生成的目标文件和可执行文件了。


给代码+Makefile提问

  • 问:用户直接将main.c编译成main.exe可以直接运行吗

​ 在Linux系统下不行。Linux 使用的可执行文件格式是 ELF(Executable and Linkable Format)。在 Linux 上需要使用对应的编译工具和环境将C/C++代码编译成Linux可执行文件,然后才能在Linux上运行。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值