Linux操作系统实验教程

更新时间:2024-03-30 20:02:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

Linux操作系统实验教程 第1章 Linux系统概述

一、Linux系统结构

从操作系统的角度来分析Linux,它的体系结构总体上属于层次结构如下图 所示:

从内到外包括三层:最内层是系统核心,中间是Shell、编译编辑实用程序、库函数等,最外层是用户程序,包括许多应用软件。

从操作系统的功能角度来看,它的核心有五大部分组成:进程管理、存储管理、文件管理、设备管理、网络管理。各子系统实现其主要功能,同时相互之间是合作、依赖的关系。进程会管理是操作系统最核心的内容,它控制了整个系统的进程调度和进程之间的通信,是整个系统合理高效运行的关键;存储管理为其他子系统提供内存管理支持,同时其他子系统又为内存管理提供了实现支持,例如要通过文件管理和设备管理实现虚拟存储器和内外存的统一管理。

二、配置一个双引导系统

如果计算机中已经安装了其他操作系统,并想创建一个引导系统以便兼用Red Hat Linux和另外的操作系统,需要使用双引导。机器启动时,可以选择其中之一,但不能同时使用两者。每个操作系统都从自己的硬盘驱动器或硬盘分区中引导,并使用自己的硬盘驱动器或硬盘分区。

如果计算机上还没有安装任何操作系统,可以使用专门的分区及格式化软件给Windows创建指定大小的分区,Windows的文件系统为FAT,再为Linux系统创建所需要大小的分区(4G或更大),另外再给Linux留100MB左右的交换分区,Linux的文件系统为ext2。然后就可以安装系统了。应首先安装Windows,然后再安装Red Hat Linux。如果只进行了分区而没有格式化各分区,在安装时可以使用Windows自带的格式化程序和Linux 自带的格式化程序进行各自分区的格式化。

当Windows已经被安装,而且已为Linux准备了足够的磁盘空间,就可以安装Linux了。Red Hat Linux安装程序通常会检测到Windows并自动配置引导程序来引导Windows或Red Hat Linux。

1

安装完成之后,无论在什么时候启动计算机,都能够在引导装载程序屏幕中指明想启动Red Hat Linux还是另外的操作系统。选择Red Hat Linux来引导Red Hat Linux;选择DOS来引导Windows。 三、Red Hat Linux的安装

将Red Hat Linux9.X安装光盘插入光驱,然后启动计算机,即可从CD-ROM启动Red Hat Linux9.X安装程序。

步骤1,机器启动之后,显示boot提示屏幕,其中包括几个不同的引导选项,每个引导选项还有一个或多个与之关联的帮助屏幕。

以图形方式从光盘中安装Red Hat Linux,单击“回车”键继续安装。 步骤2,安装程序检测用户系统并试图识别光驱。如果找到了,会进入安装进程的下一个阶段。这时若要终止安装进程,应取出光盘,重新引导机器。

步骤3,欢迎使用Red Hat Linux,欢迎屏幕并不提示做任何输入。可阅读左侧面板内的帮助文字来获得附加的说明,以及关于如何注册Red Hat Linux产品的信息。

单击next继续

步骤4,语言选择。使用鼠标选择要使用的语言。选择恰当的语言会在稍后的安装中帮助定位时区配置。安装程序将会根据这个屏幕上所指定的信息来定义恰当的时区。选择恰当的语言(例如简体中文)后,单击next继续。

步骤5, 键盘配置。用鼠标选择要在今后用作系统默认的键盘布局类型(例如U.S.English),选定后,单击next继续。

如果要在安装结束以后,想改变键盘类型,可在系统启动后窗口中单击屏幕左下角的

,弹出主菜单,选择“系统设置/键盘”,如果不是根用户,系

统会提示输入根口令再继续;或者在shell提示符下输入redhat-config-keyboard命令,如果不是根用户,系统会提示输入根口令再继续。

步骤6,鼠标配置。为系统选择正确的鼠标类型。如果找不到一个能确定与系统兼容的鼠标,可以根据鼠标的键数和它的接口,选择“通用”项目中的一个。选定鼠标型号以后,单击next继续。

如果在安装结束以后改变鼠标配置,可在系统启动后窗口中单击屏幕左下角的

,弹出主菜单,选择“系统设置/鼠标”,如果不是根用户,系统会提

示输入根口令再继续;或者在shell提示符下输入redhat-config-mouse命令,如果不是根用户,系统会提示输入根口令再继续。

步骤7,选择安装还是升级。如果安装程序在系统中检测到从前安装的Red Hat Linux版本,则“升级检查”屏幕就会自动出现。

这里考虑在系统上执行Red Hat Linux的新安装,选择“执行Red Hat Linux的新安装”,然后单击next继续。

步骤8,选择要执行的安装类型。Red Hat Linux的安装类型选项有“个人桌面”、“工作站”、“服务器”、“定制” 和“升级”。选择“个人桌面”,单击next继续。

步骤9,网络配置。安装程序会自动检测到机器中拥有的任何网络设备,并

2

把它们显示在“网络设备”列表中。选择默认选项后,单击next继续。

要在安装结束以后改变网络配置,可在系统启动后窗口中单击屏幕左下角的“红帽子

”,弹出主菜单,选择“系统设置/网络”,如果不是根用户,系

统会提示输入根口令再继续;或者在shell提示符下输入redhat-config-network命令,如果不是根用户,系统会提示输入根口令后再继续。

步骤10,为系统选择恰当的安全级别。 ? “高级”:系统不会接受那些没有被具体制定的连接(除了默认设置,例

如DNS回应、DHCP之外)。如果要把系统连接到互联网上,但是并不打算运行服务器,这是最安全的选择。如果需要额外的服务,可以选择“定制”来具体指定允许通过防火墙的服务。 ? “中级”:防火墙将不准系统访问某些资源。可以选择“定制”来具体

指定允许通过防火墙的服务。 ? “无防火墙”:给予完全访问权,且不做任何安全检查。 ? “信任的设备”:选择“信任的设备”中的任何一个可使系统接受来自

这一设备的全部通信而不受防火墙规则的限制。 ? “允许进入”:启用这些选项,将允许具体指定的服务穿过防火墙。

防火墙配置完毕,单击next继续。

要在安装完毕后改变安全级别配置,可在系统启动后的窗口中单击屏幕左下角的

,弹出主菜单,选择“系统设置/安全级别”,如果不是根用户,

系统会提示输入根口令再继续;或者在shell提示符下输入

redhat-config-securitylevel命令,如果不是根用户,系统会提示输入根口令后再继续。

步骤11,选择时区。可以通过选择计算机的物理位置,或指定时区和通用协调时间(UTC)之间的偏移来设置时区。

时区选定后,单击next继续。

要在安装完成以后改变时区配置,可在系统启动后的窗口中单击屏幕左下角的“红帽子

”,弹出主菜单,选择“系统设置/日期&时间”,如果不是

根用户,系统会提示输入根口令再继续;或者在shell提示符下输入

redhat-config-date命令,如果不是根用户,系统会提示输入根口令后再继续。

步骤12,设置根口令。设置根账号(即超级用户帐号)及其口令是安装过程中最重要的步骤之一。根账号是用来安装软件包、升级RPM以及执行多数系统维护工作。作为根用户登录可获得对系统的完全控制权。

安装程序会提示为系统设置一个根口令。如果不输入根口令,安装程序将不允许继续。

根口令必须至少包括6个字符,所输入的口令不会在屏幕上显示,口令是区分大小写的。

根口令设置完毕,单击next继续。

3

要在安装以后改变根口令,可在系统启动后的窗口中单击屏幕左下角的,弹出主菜单,选择“系统设置/根口令”,如果不是根用户,系统会提

示输入根口令再继续;或者在shell提示符下输入redhat-config-rootpassword

命令,如果不是根用户,系统会提示输入根口令后再继续。

步骤13,个人桌面的默认设置。安装程序会自动选择多数软件包。单击next继续。

步骤14,选择软件包组。在“其他”栏(组件列表的结尾处)选择“全部”以安装包括在Red Hat Linux中的所有软件包。

也可以在选择软件包组后,用鼠标选择或取消选择单个软件包。要了解某一指定软件包的详情,可单击该软件包的名称,关于它的信息将会在屏幕底部出现。某些软件包(例如内核和某些库)是每个系统所必需的,被系统默认选定,他们不能被选择或取消选择。

软件包设置完成后,单击next继续。

步骤15,至此,应该可以看到为安装Red Hat Linux而准备好的屏幕。 如果由于某种原因希望中断安装进程,此处是可以安全取消安装并重新引导系统的最后机会。一旦按下了“next”按钮,分区将会被写入,系统将会被安装。

注意:如果想中止安装,应该在信息被写入硬盘驱动器之前重新引导系统。 继续安装,单击next继续。

步骤16,安装软件包。在所有软件包安装完成之前,将不能进行任何其它操作。安装的快慢取决于所选择软件包的数量和计算机的运行速度。

依据安装程序的提示,一次插入第1、第2、第3张Red Hat Linux系统光盘。

步骤16,创建引导盘。要创建一张引导盘,可在软驱中插入一张空白的、格式化了的磁盘,然后单击next继续。

步骤17,视频卡配置。安装程序给出一个视频卡列表供选择。选定后(或接受系统的默认选择),单击next继续。

步骤18,显示器配置。安装程序给出一个显示器列表供选择。选定后(或接受系统的默认选择),单击next继续。

步骤19,定制图形化配置。设置屏幕“色彩深度”和“屏幕分辨率”(或接受系统的默认选择),单击next继续。

步骤20,安装完成。至此,安装完成。取出软驱中的软盘和光驱中的光盘。 单击“退出”按钮,来重新引导系统。一份完整的安装日志可在/root/install.log中找到,已备今后参考。

四、登录和退出Red Hat Linux系统 1、登录系统

打开计算机,选择Red Hat Linux,Linux系统开始启动,之后出现如下登录界面:

4

输入用户名,按回车,系统要求输入口令,输入口令后按回车。如果输入的用户名和口令正确,就会出现以下窗口

至此,已经进入Linux系统。 2、退出系统 单击窗口左下角的

打开主菜单,选择其中的“注销”命令,在弹出

的对话框中选择“关闭系统”,单击“确定”按钮。系统将关闭,等出现“power

5

down”字样时,可以关闭电源。

还可使用其他方法退出系统,这里不再介绍。 五、Linux系统的shell

使用Linux系统时,用户多数时间是通过shell与系统进行对话的。Shell是一个接受用户输入命令并将其转换成指令的程序,是用户与Linux系统之间的界面之一。shell 提示看起来类似你熟悉的其它命令行界面。用户在 shell 提示下键入命令,shell 解释这些命令,然后告诉 OS 该怎么做。有经验的用户可以编写 shell 脚本来进一步扩展这些功能。

要打开shell,可在启动后的窗口中,单击屏幕左下角的

即主菜单,选

择“系统工具/终端”即可进入shell。 还可以右击桌面并从菜单中选择「新建终端」来启动 shell。

Shell的界面如下:

要退出 shell 提示,点击 shell 提示窗口右上角的X 按钮,或在提示中键入 exit,或按 [Ctrl]-[D]。

Linux系统中可以使用的shell有:

bash:Bourne Again Shell。由GNU(自由软件基金会)开发。是Linux系统中最常用的shell,也是Red Hat Linux9x中默认的shell。合乎POSIX标准且与Bourne Shell兼容,提供了编辑命令行的功能。

csh:c shell。由Berkeley(伯克利大学)开发,与Bourne Shell在交互式使用上很多是兼容的,但在程序设计界面上却有很大的不同。不提供命令行编辑功能。

ksh:Korn Shell。在UNIX系统下得到普遍应用,提供了命令行编辑功能。 sh: Bourne Shell。是原始的shell,不提供命令行编辑功能。 tcsh:c shell的加强版,提供了命令行编辑功能。

zsh:z shell。最新的shell,与Bourne Shell兼容,提供了命令行编辑功

6

能。

六、Linux系统文件、目录和权限

Linux文件名没有标准格式。通常文件名可以包含任何字符(“/” 字符除外,“~” 字符不能作为文件名的第一个字符),文件名的长度限制在256个字符以内。Linux文件名也提供了强大的通配符:

? 星号(*):可以匹配任何字符串。 ? 问号(?):可匹配任何单个字符。 Linux系统中文件的权限有3种

? Read(可读)权限:可以读取文件内的数据。 ? Write(可写)权限:可以改变或删除该文件。

? Execute9(可执行)权限:可以把该文件当成程序执行。

拥有root口令的用户称为超级用户,超级用户有权访问整个系统,包括建立普通帐号、修改口令、安装及卸载软件等。超级用户的提示符为#,普通用户的提示符为$。

在Linux文件系统根目录下,有如下子目录:bin、dev、etc、home、install、lib、mnt、proc、root、tem、user、var(不同版本,目录会略有不同)。

/bin目录:该目录中存放许多基本的系统程序。

/dev目录:该目录中存放的是设备驱动程序,用来访问系统设备和资源。 /home目录:用户主目录,存放各用户的子目录。 七、加载USB存储设备

1.在插入U盘或硬盘之前,以超级用户的身份,在命令行窗口运行:fdisk -l 命令,系统将显示目前所能识别到的硬件存储设备;即:

# fdisk -l 显示内容如: sda ?? sda1 ?? sda2 ?? sdb ?? sdb1 ?? sdb2 ??

等信息,其中,sda与sdb表示目前系统有两个硬盘,后面带有数字表示各个硬盘下的各区目录;

硬盘或存储设备一般都是以sd开头. 2.插入U盘或硬盘,再次运行fdisk -l 命令,系统将再次显示目前所能识别到的硬件存储设备,比较两次输出的不同,将发现第二次运行时会增加一些内容;

系统将在原来的基础上增加显示:sdc,等内容,表示新插入的U盘或移动硬盘是挂靠在系统的sdc下.

3.运行mount命令,如:

#mkdir /mnt/usb 在mnt下建立usb(自己起的子目录名)子目录 #mount –t vfat /dev/sdc /mnt/usb

4.运行完毕,可以直接在/mnt/usb目录下,使用U盘或移动硬盘 若要显示U盘或移动硬盘中的中文文件名,可加参数“ –o”,即:可输入如下命令

#mount –t vfat /dev/sdc /mnt/usb –o iocharset=gb2312

7

5. 断开U盘或移动硬盘之前,运行umount命令,保证数据不会造成丢失,命令如下:

#umount /dev/sdc 共5个步,即

1、用root帐户登录; 2、mkdir /mnt/usb;(注:创建挂载目录)

3、mount /mnt/sda1 /mnt/usb;(注:挂载U盘)

4、现在就可以使用U盘了,在/mnt/usb目录下的内容就是U盘里的内容了; 5、使用完后,用以下命令卸载U盘即可。 #umount /mnt/usb

第2章 Linux系统的Shell命令

一、目录管理命令

1、建立目录命令(mkdir)

格式:mkdir 目录名1 目录名2 ??

常用的选项有-m,指定目录的模式,即访问权限,用3位八进制数字跟在后面表示。

例:$mkdir d1 d2 d3

在当前目录下建立了3个子目录,名字分别为d1、d2、d3 $mkdir d4 –m 775

在当前目录下建立名为d4的目录,访问权限为775,即该目录的所有者和同组用户有读、写和执行这个目录的权限,其他用户有读和执行权限。

2、删除目录(rmdir)

格式:rmdir目录名1 目录名2 ??

该命令一次可以删除多个目录,删除目录时要求目录为空。 另外,Linux系统还提供了rm命令删除目录和文件。Rm名令常用的选项有: -f:如果文件不存在则忽略,并且不提示。

-r:递归地删除目录下的内容,rm只有加了这个参数才可以删除目录。 3、改变工作目录(cd)

改变工作目录命令与PC-DOS的改变工作目录命令一样。注意,当转到别的用户目录时,能执行的操作取决于该用户赋予的权利。

格式:cd [路径名]

当不给出路径名时,cd命令的执行就转到用户的注册目录(home)中,即由环境变量$HOME指定的目录,否则,转到按路径名指定的目录。例如:

$cd d1

进入到当前目录下的d1目录中 $cd /home/y/d2

按路径名转到d2目录下。 $cd

转到y目录下。

指定路径时,可以使用相对路径,也可以用绝对路径,这一点和PC-DOS一样。

注:要转到某个目录时,必须对那个目录有执行权,否则出错。

8

4、确定当前目录所在的位置(pwd) 格式:pwd 例如:$pwd /home/y/d1

当前目录路径为:/home/y/d1 5、列出某目录下的内容(ls)

该命令与PC-DOS中的dir命令类似,列出目录下的各文件名。 格式:ls 选择项 常用的选择项有:

-l:按长格式列出每个文件的全部属性信息(如文件名、文件大小、文件的存取方法等)。

-a:列出所有的文件名,包括以“.”开始的隐含文件。 -s:对每个文件按块给出大小。

-i:在第1列给出每个文件的i节点号。 -t:按文件最后修改时间排序列出。 -R:列出包括子目录下的文件名。

6、目录、文件改名和移动目录、文件(mv) 格式1:mv 源目录名 目标目录名

功能:如果目标目录不存在,则将源目录名改为目标目录名。如果目标目录名已经存在,则将源目录移到目标目录之下,作为它的子目录。此时要求使用该命令的用户对目标目录有写权限。

格式2:mv 源文件名 目标文件名 功能:将源文件名改为目标文件名。

格式3:mv 文件名1 文件名2 ?? 目录名

功能:将文件1 文件2 ??传送到指定的目录中。 常用的选项有:

-f:如果目标文件存在,则覆盖目标文件而不提示。 -u:只复制目标中不存在的文件或更新过的文件。 7、复制目录或文件(cp)

cp命令既可以复制目录也可以复制文件

格式1:cp 选择项 源目录名?? 目标目录名

功能:将一个或多个源目录中的文件复制到目标目录下。 格式2:cp 选择项 源文件名 目标文件名 功能:把一个文件复制到另一个文件中。

格式3:cp 选择项 文件名1 文件名2?? 目录名 功能:把一个或多个文件复制到一目录中。 说明:

(1)当源目录或源文件为多个时,各目录名或各文件名之间用空格分开。 (2)将一个文件复制到目录时,该目录必须是可写的,否则复制失败。当把一个文件复制到另一个文件时,若目标文件已经存在,则覆盖之,但覆盖文件的所有者的存取权限保持不变。

常用的选择项有:

-i:当目标已经存在时,在覆盖之前,先提示是否覆盖; -f:如果目标文件存在,则覆盖目标文件而不提示;

9

-r:递归地复制源目录到目标目录;

-u:只复制目标中不存在的文件或者更新过的文件; -R:递归地复制当前目录及子目录下的文件; -p:复制时保持文件的属性; -d:复制时保持链接关系;

8、显示目录所占磁盘空间的大小(du) 格式:du 选择项 目录名 常用的选择项有:

-a:递归地显示所有目录下的文件占用的空间; -h:以可读形式列出各文件大小;

-s:只显示该目录的大小,目录中的各文件占用的空间不显示 二、文件管理

1、显示文件内容命令(cat和more) (1)连接和显示文件(cat) 格式1:cat 文件1 文件2??

功能:连续显示各文件的内容。各文件之间没有标志也没有空行。 格式2:cat>file1 功能:建立一个文件名为file1的文件。用ctrl+d组合键结束文件的输入。 格式3:cat 文件1 文件2〉文件3

功能:将文件1和文件2的内容写到文件3中。 格式4:cat文件1 文件2〉〉文件3

功能:将文件1和文件2的内容附加到文件3的末尾。 (2)分屏显示文件内容(more)

格式:more 选择项 文件1 文件2?? 如果一屏显示不完,按空格键可以显示下一屏的内容。随时按q键退出该命令。

常用的选择项有:

+行号:从文件的指定行号开始显示。

+/字符串:从文件中指定的字符串前两行开始显示。 -s:把文件中的多个空行压缩成一个空行。 2、删除文件命令(rm)

格式:rm 选择项 文件名1 文件名2?? 常用的选择项有:

-f:如果文件不存在则忽略,并且删除前不提示。

-r:递归地删除目录下的内容,只有加了该参数才可以删除目录。 3、统计文件中的行、字和字符数(wc) 格式:wc 选择项 文件名 常用的选择项有:

-l:只对指定文件中的行进行统计。 -w:只对指定文件中的字进行统计。 -c:只对指定文件中的字符进行统计。

如果没有选择项,wc的统计顺序为,先统计行,再统计字,然后统计字符。最后给出被统计的文件名。

三、其它

10

1、检查磁盘剩余空间(df) 2、echo

格式: echo [-n] word/string

此命令把每个单词或字符串写入shell的标准输出.

四、变量和参数

在shell程序中,共有6种类型的变量 1、变量的定义

定义变量的格式:变量名=表达式

用$可以取得变量的值,如:$num为num的值。 2、位置变量

位置变量是在调用shell程序的命令行中按照确定的位置决定的变量。位置变量用来存储Shell程序后面所跟的参数。第一个参数存储在变量1中,第二个参数存储在变量2中,依次类推。在程序名之后输入的每个参数之间用空格分隔。$0是当前该命令文件的名字。

例如,编写一个Shell程序reverse,执行时带两个参数。输出时,将两个参数的位置颠倒。reverse的内容为:

#program reverse, prints the command line parameters out in reverse order echo \

在Shell下执行此Shell程序:reverse hello there 其输出为:there hello

3、shell预定义变量

有些变量在执行Shell程序时系统就设置好了,并且不能加以修改: $# 存储运行Shell程序时输入的位置参数的个数。 $? 存储上一个执行命令的返回值。

$* 存储从第一个位置参数开始的所有位置参数的内容。

$@ 存储所有命令行输入的参数,分别表示为“$ 1”,“$ 2” . . . 。 $$ 存储当前执行进程的进程标识PID。

$! 存储上一个后台执行命令的进程标识PID。

五、运算符和表达式 Shell中的运算符包括

运算符 文件运算符 -e filename -d filename -f filename -L filename -r filename -w filename

如果 filename存在,则为真 如果 filename为目录,则为真 如果 filename为常规文件,则为真

如果 filename为符号链接,则为真

如果 filename可读,则为真 如果 filename可写,则为真

11

描述 示例

[ -e /var/log/syslog ] [ -d /tmp/mydir ] [ -f /usr/bin/grep ] [ -L /usr/bin/grep ] [ -r /var/log/syslog ] [ -w /var/mytmp.txt ]

-x filename filename1-nt filename2 filename1-ot filename2

如果 filename可执行,则为真 如果 filename1比 filename2新,则为真

如果 filename1比 filename2旧,则为真

[ -L /usr/bin/grep ] [ /tmp/install/etc/services -nt /etc/services ] [ /boot/bzImage -ot arch/i386/boot/bzImage ]

字符串比较运算符 (请注意引号的使用,这是防止空格扰乱代码的好方法) -z string -n string string1== string2 string1!= string2 算术比较运算符 num1-eq num2 num1-ne num2

num1-lt num2 小于 小于或等于 num1-le num2 num1-gt num2 num1-ge num2 算术运算符: + - * / %

大于或等于

[ 3 -ge $mynum ] [ - 3 ] [ 3 + 5 ] [ 8 – 3 ] [ 2 \\* 3 ] [ 6 \\/ 2 ] [ 5 % 2 ]

大于

[ 3 -lt $mynum ] [ 3 -le $mynum ] [ 3 -gt $mynum ]

不等于

[ 3 -ne $mynum ]

等于

[ 3 -eq $mynum ]

如果 string长度为零,则为真 如果 string长度非零,则为真 如果 string1与 string2相同,则为真

如果 string1与 string2不同,则为真

[ -z \[ -n \

[ \three\

[ \three\

(在*和/之前必须冠以反斜线“\\”)

加号 减号 乘号 除号 取余

- 负号

在脚本程序中可以用运算符将运算对象连接起来构成的式子称为表达式。

六、shell控制语句 1、if语句

格式1:if [ 条件表达式 ] then 命令序列 fi

格式2:if [ 条件表达式 ]

12

then 命令序列 else 命令序列 fi

格式3:if [ 条件表达式 ] then 命令序列

elif [ 条件表达式 ] then 命令序列 else 命令序列 fi

格式4:if test 条件表达式 then 命令序列

{elif test 条件表达式 then 命令序列 .

. .

}

else 命令序列 fi 说明:

(1)格式1、格式2、格式3中的“[”和“]”两侧要留有空格

(2)格式4中的“{}”不属于if语句中的符号,只在本格式中说明“{}”中的内容可以重复出现多次。 2、for循环语句

格式1:

for 变量 in 值表 do 命令表 done

格式2:

for 变量 in 文件正则表达式 do 命令表 done

其执行过程是,变量的值依次取当前目录下(或给定目录下)与正则表达式相匹配的文件名,每取值一次,就进入循环体执行命令表,直至所有匹配的文件名取完为止,退出for循环。

格式3:

for i in $* 或者 for i do do 命令表 命令表 done done

这两种形式是等价的。其执行过程是,变量i 依次取位置参数的值,然后执行循环体

13

中的命令表,直至所有位置参数取完为止。

3、while循环语句 格式:

while条件表达式 do 命令表 done

其执行过程是,先进行条件测试,如果结果为真,则进入循环体(do—done之间部分), 执行其中命令;然后再做条件测试……直至测试条件为假时才终止while语句的执行。 4、until语句 格式:

until 条件表达式 do 命令表 done

它与while语句很相似,只是测试条件不同:当测试条件为假时,才进入循环体,直至测试条件为真时终止循环。 5、break语句和continue语句

break语句可以使我们从循环体中退出来。 格式: break [ n ]

其中,n表示要跳出几层循环。默认值是1,表示只跳出一层循环。

continue语句跳过循环体中在它之后的语句,回到本层循环的开头,进行下一次循环。 格式: continue [ n ]

其中,n表示从包含continue语句的最内层循环体向外跳到第几层循环。默认值为1。循环层数是由内向外编号。 6、case语句

case语句允许进行多重条件选择。 格式:

case 字符串 in

模式字符串1) 命令序列1 … ; ;

模式字符串2) 命令序列2 … ; ; …

模式字符串n) 命令序列n … ; ;

14

esac

其执行过程是用―字符串‖的值依次与各模式字符串进行比较,如果发现同某一个匹配,那么就执行该模式字符串之后的各个命令,直至遇到两个分号为止。如果没有任何模式字符串与该字符串的值相符合,则不执行任何命令。 在使用case语句时应注意:

(1)每个模式字符串后面可有一条或多条命令,其最后一条命令必须以两个分号(即;;)结束。

(2)模式字符串中可以使用通配符。

(3) 如果一个模式字符串中包含多个模式,那么各模式之间应以竖线(|)隔开,表示各模式是―或‖的关系,即只要给定字符串与其中一个模式相配,就会执行其后的命令表。

(4)各模式字符串应是惟一的,不应重复出现。并且要合理安排它们的出现顺序。例如,不应将―*‖作为头一个模式字符串,因为―*‖可以与任何字符串匹配,它若第一个出现,就不会再检查其它模式了。

(5)case语句以关键字case开头,以关键字esac(是case倒过来写!)结束。 (6)case的退出(返回)值是整个结构中最后执行的那个命令的退出值。若没有执行任何命令,则退出值为零。 7、expr语句

虽然shell并不精于数值计算,但还是提供了有关的计算语句。

格式:

expr 表达式1 表达式2 ??

表达式中只允许整数,合法的运算符有+、-、*、/和%(取余),在*(乘号)和/(除号)之前必须冠以\\(反斜杠),以防这些运算符由expr获得之前被shell解释。

例如:$expr 3 \\* 5 + 2 \\/ 2 16

注意:运算符两侧要留有空格。 8、read语句

利用read语句命令可以从键盘上读取数据,然后赋给指定的变量

格式:

read 变量1 变量2 ?? 例如:read x y z

输入数据时,数据间以空格或制表符作为分隔符。如果变量个数与给定数据个数相同,则依次对应赋值;如果变量个数少于数据个数,则从左至右对应赋值,但最后一个变量被赋予剩余的所有数据;如果变量个数多于给定数据个数,则依次对应赋值,而没有数据与之对应的变量取空串。

9、举例

例1 从控制台接收用户输入,并在标准输出设备上显示结果 echo ―Are you girl?please answer Y or N‖ read sex

if [ $sex == ―Y‖ ];then echo ―Hello girl!‖ echo ―How are you!‖ else echo ―Hello boy!‖

15

echo ―How do you do!‖ fi

echo ―ABC‖ exit 0 例2

echo ―Are you girl?please answer Y or N‖ read sex

if test $sex == ―Y‖ then echo ―Hello girl!‖ elif test $sex== ―N‖ then echo ―Hello boy!‖ else

echo ―sorry,$sex not recognized,please entey Y or N‖ exit 1 fi exit 0 例3

for day in Mon Tue Wed Thu Fri Sat Sun do

echo $day done

其执行过程是,变量day依次取值表中各字符串,即第一次将―Mon‖赋给day,然后进入循环体,执行其中的命令,显示出Mon。第二次将―Tue‖赋给day,然后执行循环体中命令,显示出Tue。依次处理,当day把值表中各字符串都取过一次之后,下面day的值就变为空串,从而结束for循环。因此,值表中字符串的个数就决定了for循环执行的次数。在格式上,值表中各字符串之间以空格隔开。

例4

while [ $1 ] do

if [ -f $1 ]

then echo \cat $1

else echo \fi shift done

这段程序对各个给定的位置参数,首先判断其是否是普通文件,若是,则显示其内容;否则,显示它不是文件名的信息。每次循环处理一个位置参数$1,利用shift命令可把后续位置参数左移。

测试条件部分除使用test命令或等价的方括号外,还可以是一组命令。根据其最后一个命令的退出值决定是否进入循环体执行。 例5 编写一个简单的删除程序

#name: del

16

#author: liangnian

#this program to compress a file to the dustbin if test $# -eq 0 then

echo ―Please specify a file!‖ else

gzip $1 //先对文件进行压缩

mv $1.gz $HOME/dustbin //移动到回收站 echo ―File $1 is deleted !‖

fi

10、Shell脚本的建立和执行 (1)Shell脚本的建立

Shell程序可以存放在文件中,这种被Shell解释执行的命令文件称为Shell脚本 (Shell Script)。Shell脚本可以包含任意从键盘键入的Linux命令。

建立Shell脚本的步骤同建立普通文本文件的方式相同,利用任何编辑器(如vi)进行程序录入和编辑加工。例如,要建立一个名为ex1的Shell脚本,可在提示符后输入命令:

$ vi ex1

进入vi的插入方式后,就可录入程序行。完成编辑之后,将编辑缓冲区内容写入文件中,返回到Shell命令状态。 (2)执行Shell脚本

格式:$ bash 脚本名 [参数] 例如:

$ bash ex1 /usr/meng /usr/zhang

Shell从文件ex1中读取命令行,并执行它们。当Shell到达文件末尾时就终止执行,并把控制返回到Shell命令状态。若有参数,则将参数值传递给程序中的命令,使一个Shell脚本可以处理多种情况,就如同函数调用时可根据具体问题给定相应的实参。

第3章 Linux系统调用函数简介

1、fork( ):创建一个新进程 格式:int fork()

其中返回int值的意义如下: 0:创建子进程,从子进程返回

>0:从父进程返回,返回值为子进程的进程标识符 -1:创建失败

2、vfork( ):创建一个新进程

17

格式:int vfork()

其中返回int值的意义如下: 0:创建子进程,从子进程返回

>0:从父进程返回,返回值为子进程的进程标识符 -1:创建失败

vfork()和fork()不同之处在于:在fork调用中,子进程复制父进程的数据区作为自己的数据区,能够继承已有的资源,从而对数据的操作不再影响父进程。vfork()函数在创建子进程后,先于父进程运行,父进程被阻塞,在子进程调用exec或exit之前,子进程与父进程共享数据段,此时可对父进程的数据进行操作。

3、execv():运行可执行文件

格式:int execv(const char *file,char **argv,char **envp) 其中返回int值的意义如下: 0:正确返回 -1:错误返回

当一个进程调用execv函数执行另一个程序后,这个进程被新程序取代,包括代码段、数据段、堆栈段等等,并继承原进程的进程标识符。从自己的main()函数开始执行。新程序使用原进程的进程标识符和进程控制表里的一部分信息。

该函数要用到unistd.h头文件,即在程序中要有#include 4、wait():进程的等待

Wait函数常用来控制父进程与子进程的同步。在父进程中调用wait函数,则父进程被阻塞,进入等待队列,等待子进程结束。当子进程结束时,会产生一个终止状态字,系统会向父进程发出SIGCHLD信号。当接收到信号后,父进程提取子进程的终止状态字,从wait返回继续执行原程序。该函数适用的头文件如下:

#include #include

函数格式:pid_t wait(int *statloc) 子进程ID:正确返回 0:其他 -1:错误返回

可以使用系统提供的宏来获得子进程终止时的信息,这些宏定义在sys/wait.h头文件中,具体含义如下:

WIFEXITED(status):子进程正常终止,返回真。 WEXITSTATUS(status):如果WIFEXITED返回真,则该宏返回子进程的exit码。

WIFSIGNALED(status):子进程非正常终止,返回真。 WTERMSIG(status):如果WIFSIGNALED返回真,则该宏返回引起子进程终止的信号值。

WIFSTOPPED(status):子进程已结束,返回真。 WSTOPSIG(status):如果WIFSTOPPED返回真,则该宏返回引起子进程结束的信号值。

5、waitpid()

18

如果父进程创建了多个子进程同时在运行,则父进程中wait函数会捕获它任一个子进程的结束信号,而无法让它确定地去捕获某一个进程的结束信号。Waitpid函数则解决了这个问题。该函数适用的头文件如下:

#include #include

函数格式:pid_t waitpid(pid_t pid,int *statloc,int options) 子进程ID:正确返回 0:其他 -1:错误返回

参数pid的值决定要求父进程等待的不同特征的子进程,含义如下: 0:与父进程组ID相同的子进程。 >0:进程ID为pid的子进程。

-1:任意子进程。此时与wait函数功能相同。 <-1:进程组ID为pid绝对值的子进程。

Statloc所指的地址用于存放子进程的终止状态字。 Options控制waitpid的执行,常用的参数如WNOHANG:若waitpid函数没得到指定子进程的结束信号,则立即返回零,不会阻塞。

6、exit():结束进程

进程结束最常用的方法是调用exit函数,在main函数中调用的return,最终也是调用exit,这些都属于进程的正常终止。该函数适用的头文件如下:

#include

函数格式:void exit(int status)

Status为进程结束状态。在子进程调用exit后,子进程的结束状态会返回给系统内核,由内核根据状态字生成终止状态,供父进程在wait或waitpid函数中读取。如果子进程结束后,父进程还没有读取子进程的终止状态,则系统就将子进程的状态置为“ZOMBIE”,并保留子进程的进程控制块,里面记录着进程标识符、终止状态字、CPU时间等信息,等父进程读取信息后,系统才彻底释放子进程的进程控制块。

7、msgget():获得一个消息的描述符,该描述符指定一个消息队列以便用于其他系统调用。

该函数适用的头文件如下: #include #include #include

函数格式:int msgget(key,flag) key_t key; int flag ;

消息队列的标识符:正确返回 -1: 错误返回 Key是键值,这个键值要与已有的键值进行比较,已有的键值指在内核中已存在的其他消息队列键值。当key的值为IPC_PRIVATE时,创建一个新的消息队列;当key的值不为IPC_PRIVATE时,对消息队列的打开或存取操作依赖于flag参数的取值。

8、msgsnd():发送一条消息给一个消息队列

19

该函数适用的头文件如下: #include #include #include

函数格式:int msgsnd(id,smgp,size,flag) int id,size,flag; struct msgbuf* msgp; 消息队列的标识符:正确返回 -1:错误返回

其中:id是返回消息队列的标识符;msgp是指向用户存储区的一个构造体指针,size指示由msgp指向的数据结构中字符数组的长度,即消息队列的长度;flag规定当核心用尽内部缓冲空间时应执行的动作;若在标志flag中未设置IPC_NOWAIT位,则当该消息队列中的字节数超过一最大值时,或系统范围的消息数超过某一最大值时,则调用进程将被阻塞,进入等待队列;若设置IPC_NOWAIT,msgsnd立即返回。

9、msgrcv():从消息队列中接受消息,,将该消息拷贝到消息缓冲区中,返回拷贝的字节数。

该函数适用的头文件如下: #include #include #include

函数格式:int msgsnd(id,smgp,size,type,flag)

int id,size,type,flag;

struct msgbuf* msgp;

接收到消息缓冲区的字节数:正确返回 -1:错误返回

其中,id指定要接收的消息队列;msgp是存放消息的消息缓冲区的地址指针;size是消息缓冲区的大小;type是用户要读的消息类型,取值有三种:

(1)type>0:查找消息队列中与该类型相匹配的第一条消息。 (2)type==0:接收该队列的第一个消息。

(3)type<<0:接收小于或等于type绝对值的最低类型的第一个消息。 flag的含义同上一个函数,如果值为IPC_NOWAIT,并且没有可取的消息,则带错返回调用进程。否则,调用进程阻塞进入阻塞队列,直到一条消息到达队列并且满足接收条件。

10、lockf(files,mode,size):用于锁定文件的某些段或者整个文件. 本函数的头文件为 #include unistd.h 函数格式:

int lockf(files,mode,size) int files,mode; long size;

其中:files是文件描述符;mode是锁定和解锁:1表示锁定,0表示解锁.size是锁定或解锁的字节数,为0,表示从文件的当前位置到文件尾.

20

第4章 屏幕编辑程序vi简介

Vi是UNIX/Linux系统自带的功能强大的可视化的编辑器。 一、进入和退出vi

1、在Linux提示符下键入“vi 文件名”即可启动vi Vi有以下3种工作模式:

(1)命令行模式:进入vi时处于命令模式。输入某些编辑命令后可对文本进行编辑。

(2)文本输入模式:在命令模式下,按下a键,进入追加方式,以后输入的字符插入在光标的右边;按下i键,进入插入方式,以后输入的字符插入在光标的左边;按下r键,进入覆盖方式,以后输入的字符覆盖光标处的字符。

(3)最后行模式:在文本输入模式下,按ESC键,结束输入模式,再输入冒号“:”就进入最后行模式了,还可以使用“?”键和“/”键进入最后行模式。 2、要退出vi,先按下ESC键,退出输入模式,再键入冒号“:”,此时光标会停留在最下面一行,即进入最后行模式,再按“q”键,按回车键即可。

例如:上一章列举的shell脚本程序都可以用vi建立。在shell提示符$下键入:vi ex2.sh ,回车,可进入vi,按i键后,可输入脚本程序内容。

也可以用vi建立c语言程序,在shell提示符$下,键入vi 程序名.c,回车,可进入vi,按i键后,可输入c语言程序内容了。 二、命令模式和文本输入模式下的主要操作命令

命令模式和文本输入模式提供了较多的按键和组合键来执行命令,以帮助用户编辑文件。由于这些命令较多,这里只作简单介绍。 1、移动光标命令

可以利用键盘上的上左右箭头键来移动光标到指定的位置,还可以用一般的键来移动光标。 h :光标左移一个字符 l :光标右移一个字符 space:光标右移一个字符 Backspace:光标左移一个字符 k或Ctrl+p:光标上移一行 j或Ctrl+n :光标下移一行

w或W :光标右移一个字至下一个字的字首 b或B :光标左移一个字至前一个字的字首 e或E :光标右移到当前字的字尾 nG:光标移至第n行首 n+:光标下移n行 n-:光标上移n行 n$:光标移至第n行尾 H :光标移至屏幕顶行 M :光标移至屏幕中间行 L :光标移至屏幕最后行

0:(注意是数字零)光标移至当前行首 $:光标移至当前行尾 2、屏幕翻滚类命令

21

Ctrl+u:向文件首翻半屏 Ctrl+d:向文件尾翻半屏 Ctrl+f:向文件尾翻一屏 Ctrl+b:向文件首翻一屏

nz:将第n行滚至屏幕顶部,不指定n时将当前行滚至屏幕顶部。 3、插入文本类命令 i :在光标前插入文本 I :在当前行首插入文本 a:光标后插入文本 A:在当前行尾插入文本 o:在当前行之下新开一行 O:在当前行之上新开一行 r:替换当前字符

R:替换当前字符及其后的字符,直至按ESC键

s:从当前光标位置处开始,以输入的文本替代指定数目的字符 S:删除指定数目的行,并以所输入文本代替之 ncw或nCW:修改指定数目的字 nCC:修改指定数目的行 4、删除命令

ndw或ndW:删除光标处开始及其后的n-1个字 do:删至行首 d$:删至行尾

ndd:删除当前行及其后n-1行

x或X:删除一个字符,x删除光标后的,而X删除光标前的 Ctrl+u:删除输入方式下所输入的文本 5、搜索及替换命令

/字符串:从光标开始处向文件尾搜索“字符串” ?字符串:从光标开始处向文件首搜索“字符串” n:在同一方向重复上一次搜索命令 N:在反方向上重复上一次搜索命令

:n1,n2s/p1/p2/g:将第n1至n2行中所有p1均用p2替代 三、最后行模式下的操作命令

:n1,n2 co n3:将n1行到n2行之间的内容拷贝到第n3行下 :n1,n2 m n3:将n1行到n2行之间的内容移至到第n3行下 :n1,n2 d :将n1行到n2行之间的内容删除 :w :保存当前文件

:e filename:打开文件filename进行编辑 :x:保存当前文件并退出 :q!:不保存文件并退出vi

: wq 将缓冲区内容写入磁盘中,并退出vi。 : ZZ 同wq : q 退出vi,若文件被修改过,则要求确认是否放弃修改的内容,此指令可与: w 配合使用。

22

第5章 gcc编译器简介

当用户把Red Hat Linux9.x安装好之后,gcc也已经安装好了。Gcc是Linux平台下的标准c编译器,功能强大。下面对gcc的基本使用作简要介绍。

二、简单的c语言程序

下面通过一个非常简单的c语言程序来说明gcc编译器的使用,c语言程序如下 #include int main(void) {

Printf(”Hello world!\\n”); }

该程序的文件名为:exam.c,用户可以使用gcc编译器对exam.c进行编译,gcc的可执行文件在/usr/bin目录下,/lib和/usr/lib目录下是库文件,/usr/include目录下是头文件。

在shell提示符$下键入

gcc exam.c //编译exam.c程序 gcc将创建一个名叫a.out的文件,然后使用下面命令执行该程序。在shell提示符下键入:./a.out

“./”表示执行当前目录下的可执行文件或脚本程序。 最后输出结果如下: Hello world!

这就是Linux平台上编译的一个c语言程序。

我们还可以通过使用选项-o来改变编译后的目标文件名,例如可以使用下面的命令行把a.out改成exam1.out。

gcc –o exam1.out exam.c

这时可执行文件名就改变成exam1.out了,而不是a.out。如同运行a.out一样可以运行exam1.out。如下命令行所示

$./exam1.out

会得到同样的运行结果。 二、gcc选项简介

gcc的完整格式:gcc 选项 文件名

gcc命令行按“选项”指定的操作对给定的文件进行编译处理。在gcc后面可以有多个编译选项,同时进行多个编译操作。Gcc的主要选项有:

-x language: 指定使用的语言(c、c++或汇编) -c :只对文件进行编译和汇编,但不进行连接 -S :只对文件进行编译,但不汇编和连接

-E :只对文件进行预处理,但不编译、汇编和连接

-o file1 file2:将文件file2 编译成可执行文件file1 -I library:用来指定所使用的库文件

-I directory:为include文件搜索指定目录 -w :禁止警告信息

-pedantic:严格要求符合ANSI标准 -wall:显示附加的警告信息 -g :显示排错信息以便于调试

23

-p :产生prof所需的信息

实验一 熟悉Linu环境x -pg :产生gprof所使用的信息

-O(-OI):对编译出的代码进行优化 1、实验目的 -O2:进行比-O高一级的优化 (1)了解Linu操x作系统的 启动过 程。-O3:产生更高级别的优化(2)了解Ligccnu文x件 的组织结构 。-v:显示版本(3)练习使用Linu常x用命令 。注意:区分选项字母的大小写 (4)学中总共有一百多个编译选项,其中很多选项用户可能永远也不会用到,习和掌s握hel编l程的常用方法 。gcc2、实验要求 而很多选项用户只会偶尔用到,所以这里只给出一些主要的选项。 (1)查看Linu操x作系统目录结 构 。 (2)练习Linu常x用命令 。(3)理解命令接口的命令 形式

(4)将例题输入运行,s体he会l编l程方法 。

3、实验内容 (1)练习linu常x用命令,常用命令有s、mkdi、rrm、cp、pw?d? l: 编程(2)输入以下程序并执行,sh体e会ll技巧 1)输入下列程序并存为e文x1件.sh #!/bin /csh

va”rh=ell”o echo $var

no ec”hTohe program $0 is”w running ” ec”hTohe first paramete r was $1 ec”hTohe second paramete r was $2 ”ech”oThe parameter li”st was $* ec”hTohe us’esr home dir ectory” i s $HOME w word ech”oplease enter a ”n e read var echo $var

exi t 0 2)输入下列程序并存为e文x2件. s h #!/bin/c sh count =1 While test $–coluen t5

d o echo” here is c”y cle count=$(($cou nt+1))

don e exit 0

第六章 实 验

24

实验一 熟悉Linux环境

1、实验目的

(1)了解Linux操作系统的启动过程。 (2)了解Linux文件的组织结构。 (3)练习使用Linux常用命令。

(4)学习和掌握shell编程的常用方法。 2、实验要求

(1)查看Linux操作系统目录结构。 (2)练习Linux常用命令。 (3)理解命令接口的命令形式

(4)将例题输入运行,体会shell编程方法。 3、实验内容

(1)练习linux常用命令,常用命令有:ls、mkdir、rm、cp、pwd?? (2)输入以下程序并执行,体会shell编程技巧

1)输入下列程序并存为文件ex1.sh #!/bin/csh var=”hello” echo$var

echo”The program $0 is now running ” echo”The first parameter was $1” echo”The second parameter was $2”

echo”The parameter list was $*”

echo”The user’s home directory is $HOME” echo”please enter a new word” read var echo $var exit 0

2)输入下列程序并存为文件ex2.sh #!/bin/csh count=1

While test $count –le 5 do

echo ”here is cycle” count=$(($count+1)) done exit 0

25

实验二 进程管理

1、实验目的

(1)加深对进程概念的理解,明确进程和程序的区别 (2)进一步认识并发进程执行的实质 (3)掌握常用的系统调用命令

(4)学习和掌握进程调度的基本原理和实现方法。 2、实验要求

(1)阅读Linux的sched.h源代码文件,加深对进程管理概念的理解。 (2)阅读Linux的fork.c源代码文件,分析进程的创建过程。 3、实验内容

(1)编写一段程序,使用系统调用fork()创建两个子进程。当此程序运行时,在系统中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符:父进程显示字符“a”;子进程分别显示字符“b”和字符“c”。试观察程序执行结果,并分析原因。

(2)修改已编写好的程序,将每个进程输出一个字符改为每个进程输出一句话。试观察程序执行结果,并分析原因。

如果在程序中使用系统调用lockf()来给每个进程加锁,可以实现进程之间的互斥,观察执行结果并分析原因。 (3)

1)编制一段程序,使其实现进程的软中断通信。

要求:使用系统调用fork()创建两个子进程,再用系统调用signal()让父进程捕捉键盘上来的中断信号(即按DEL键);当捕捉到中断信号后,父进程用系统调用kill()向两个子进程发出信号,子进程捕捉到信号后分别输出下列信息后终止。

Child Processl1 is killed by Parent! Child Processl2 is killed by Parent!

父进程等待两个子进程终止后,输出下列信息后终止。 Parent Process is Killed!

2) 在上面的程序中增加语句signal(SIGINT,SIG-IGN)和 signal(SIGQUIT,SIG-IGN),观察执行结果,并分析原因。

实验三 存储管理

1、实验目的

26

操作系统的发展使得系统完成了大部分的内存管理工作,对于程序员而言,这些内存管理的过程是完全透明的。因此程序员从不关心系统如何为自己分配内存,而且永远认为系统可以分配给程序所需要的内存。在开发程序时,程序员真正需要做的就是:申请内存、使用内存、释放内存。该实验就是帮助读者更好地理解从程序员的角度应如何使用内存。 2、实验要求

研读Linux系统目录下相关源程序文件,理解源程序的设计思想和编程技巧。 3、实验内容

(1)编写程序:申请内存、使用内存及释放一块内存。 (2)在上述实验的基础上重新分配内存。 (3)使用自动分配内存函数分配内存。

实验四 文件管理

27

1、实验目的

学习和掌握文件控制的基本原理和常用的系统调用。 2、实验要求

研读Linux系统目录下相关源程序文件,理解源程序的设计思想和编程技巧。

3、实验内容 (1)利用用户自定义的缓冲区,使对文件的单字节读/写操作在缓冲区中进行,只有当用户缓冲区空或满时,才调用read/write从(或“向”)文件读、写数据。 (2)设计一交互工具,使用该工具可以查看文件的状态信息;改变文件的模式、访问时间;显示目录文件内容并在其中执行任意的shell命令。

实验五 综合实验

28

1、实验目的

综合所学各章的知识,练习在Linux环境下的综合编程能力。 2、实验内容

编程实现多个用户同时提交打印请求,并按序打印用户要求的文件。 要求:该实例主要包括两大部分

(1)sched守护进程,负责接受用户的打印请求并打印用户文件。 (2)lpp命令,用户用lpp命令提交打印请求。 提示:

第七章 实验指导

29

实验一 熟悉Linux环境

3、实验内容

(1)练习linux常用命令 1)列出文件列表的ls命令

作用:显示当前目录有哪些文件和子目录。不加任何参数 :显示当前目录的内容。 -a 显示所有文件和目录(若无此参数,句点开始的文件和目录不会显示出来) -A 显示所有文件和目录(它比-a 少显示.和..两项)

-F 在特殊文件或目录上加上标示(子目录后加 /,程序文件后加上*) -l 以长格式显示。会显示文件或目录的详细信息。

例:ls ls –a

ls -al //参数的混合使用

ls -l | more //符号|为管道操作,将ls –l的输出作为more的输入

2)切换目录cd命令

cd .. 切换到上一级目录 cd / 切换到根目录 cd ~ 切换到用户目录 “.” 表示当前目录。

cd 切换到指定的路径

3)建立目录的mkdir 命令

mkdir data 在当前目录下建立data子目录 mkdir /data 在根目录下建立子data目录

注意: 用户不能在一个不存在的目录下建立子目录。

4)删除目录的rmdir命令

rmdir 可用来删除空的子目录。 rmdir data rmdir /data

注意:如果要删除具有文件或子目录的目录,用rm会比较方便。

5)拷贝文件的cp命令

cp data1.txt data2.txt cp data3.txt /tmp/data 关于cp命令的参数。

-i 覆盖相同文件名称前先询问用户。 -v 显示命令的执行过程

-r 递归拷贝,即拷贝时将所有目录一并拷贝。

6)删除文件或目录的rm命令 rm data.txt rm *

参数说明:

30

-f 强迫删除文件,不询问用户

-r 递归删除。(将参数中列出的全部目录和子目录删除) -i 进行交互式删除

7)more命令:每次以一个page显示

一般和别的命令用管道符配合使用。例如: ls -l |more

8)cat命令: 显示文件的内容

cat data.txt 显示文件的内容

9)移动或更改文件名的mv命令

mv data.txt .. 移动文件 mv data1.txt data2.txt 更改文件名 10)显示目前所在目录的pwd命令

pwd

11)重定向与管道符

| 管道操作,前一个命令的输出是后一个命令的输入

〉 可将结果输出到文件中,如果该文件原来就存在,则该文件原有内容会被删除。

》 将结果附加到文件后面,原文件内容不会被清除。 ls –l > dir.txt

cat data1.txt>> all_data.txt 12)chmod命令:修改文件的权限 chmod u+rwx file1 chmod u-x file1 chmod g+rw,o+r file1 //同组用户对file1增加权限是可读、可写,其它用户则只能读

chmod 700 file1

13)ps命令: 查询正在执行的进程

(2)输入以下程序并执行,体会shell编程技巧

启动Linux,输入用户名和密码;“系统工具/终端”进入shell,在提示符下键入 vi ex1.sh,回车,进入vim编辑系统,按I,或a或o进入输入模式,键入该程序,结束后,按Esc键进入命令模式,按“:”进入最后行模式,按wq回车,存盘并退出vim,在shell下执行ex1.sh程序.

1)输入下列程序并存为文件ex1.sh #!/bin/csh var=”hello” echo$var

echo”The program $0 is now running ” echo”The first parameter was $1” echo”The second parameter was $2” echo”The parameter list was $*”

31

echo”The user’s home directory is $HOME” echo”please enter a new word” read var echo $var exit 0

键入‖sh ex1.sh one two thre‖ 或 ‖sh>ex1.sh one two thre‖ 运行结果为: Hello

The program ex1.sh is now running The first parameter wse one The second parameter wse two The parameter list wse one two thre The user‘s home directory is /home/y Please enter a new word Baby Baby

2)输入下列程序并存为文件ex2.sh

#!/bin/csh count=1

While test $count –le 5 do

echo ”here is cycle” count=$(($count+1)) done exit 0

运行结果为:here is cyle

here is cyle here is cyle here is cyle here is cyle

实验二 进程管理

3、实验内容 (1)参考程序

# include main()

{ int p1, p2;

while((p1=fork())= = -1);

32

if(p1= =0) putchar(?b‘); else

{ while((p2=fork())= =-1); if(p2= =0) putchar(?c‘); else

putchar( ?a‘); } }

在shell提示符下键入vi jc1.c,进入vi编辑状态,在此状态下输入上述程序。完毕后按ESC键,按:,键入wq,推出vi。 在shell提示符下键入 cd /usr/bin

gcc296 –o /home/y/jc1.out /home/y/jc1.c cd

执行程序: ./jc1.out

运行结果:bca

(2) # include

main()

{ int p1, p2, i;

while((p1=fork())== -1); if(p1==0)

for(i=0;i<5;i++)

printf(“child%d\\n”,i); else

{ while((p2=fork())==-1); if(p2==0)

for(i=0;i<5;i++)

printf(“son%d\\n”,i); else

for(i=0;i<5;i++)

printf(“daughter%d\\n”,i); } } 操作同上 运行结果: child0 child1 child2 child3 child4 son0 son1

33

son2 son3 son4

daughter0 daughter1 daughter2 daughter3 daughter4

在程序中加入系统调用lockf()

#include main()

{ int p1, p2, i;

while((p1=fork())== -1); if(p1==0) {

lockf(1,1,0); /*加锁,这里第一个参数为stdout(标准输出设备的描述符)*/ for(i=0;i<5;i++)

printf(“child%d\\n”,i);

lockf(1,0,0); /*解锁*/ }

else

{ while((p2=fork())==-1); if(p2==0)

{

lockf(1,1,0); /*加锁*/ for(i=0;i<5;i++)

printf(“son%d\\n”,i);

lockf(1,0,0); /*解锁*/ }

else {

lockf(1,1,0); /*加锁*/ for(i=0;i<5;i++)

printf(“daughter%d\\n”,i); lockf(1,0,0); /*解锁*/

} } }

运行结果和上一个相同

分析:因为上述程序执行时,不同进程之间不存在共享临界资源问题,所以加

锁与不加锁效果相同。 (3)

1)编制一段程序,使其实现进程的软中断通信。

34

要求:使用系统调用fork()创建两个子进程,再用系统调用signal()让父进程捕捉键盘上来的中断信号(即按DEL键);当捕捉到中断信号后,父进程用系统调用kill()向两个子进程发出信号,子进程捕捉到信号后分别输出下列信息后终止。

Child Processl1 is killed by Parent! Child Processl2 is killed by Parent!

父进程等待两个子进程终止后,输出下列信息后终止。 Parent Process is Killed!

参考程序:

#include #include #include void waiting( ),stop( ); int wait_mark; main() {

int p1,p2;

while((p1=fork())==-1); if(p1>0) {

while((p2=fork())==-1); if(p2>0) {

wait_mark=1;

signal(SIGINT,stop); waiting(0); kill(p1,16); kill(p2,17); wait(0); wait(0);

printf(―parent process is killed!\\n‖); exit(0); } else {

wait_mark=1; signal(17,stop); waiting( );

lockf(stdout,1,0);

printf(―child process2 is killed by parent!\\n‖); lockf(stdout,0,0); exit(0);

}

35

} else {

wait_mark=1; signal(16,stop); waiting( );

lockf(stdout,1,0);

printf(―child process1 is killed by parent!\\n‖); lockf(stdout,0,0);

exit(0); } }

void waiting()

{while(wait_mark!=0);} void stop( )

{ wait_mark=0;}

2) 在上面的程序中增加语句signal(SIGINT,SIG-IGN)和 signal(SIGQUIT,SIG-IGN),观察执行结果,并分析原因。

参考程序:

#include #include #include int pid1,pid2; int EndFlag=0; pf1=0; pf2=0;

void IntDelete() {

kill(pid1,16); kill(pid2,17); EndFlag=1; }

void Int1() {

printf(―child process1 is killed! By parent\\n‖); exit(0); }

Void Int2( ) {

printf(―child process2 is killed! By parent\\n‖); exit(0); }

36

main() {

int exitpid;

signal(SIGINT,SIG_IGN); signal(SIGQUIT,SIG_IGN);

while((pid1=fork())==-1); if(pid1==0) {

signal(SIGUSR1,Int1);

signal(SIGINT,SIG_IGN); pause( ); exit(0); } else {

while((pid2=fork())==-1); if(pid2==0) {

signal(SIGUSR1,Int1);

signal(SIGINT,SIG_IGN); pause( ); exit(0);

} else {

signal(SIGINT,IntDelete); waitpid(-1,&exitcode,0);

printf(―parent process is killed!\\n‖); exit(0); }

} }

分析:由于忽略了中断与退出信号,程序会一直保持阻塞状态而无法退出。

实验三 存储管理

3、实验内容

(1)编写程序:申请内存、使用内存及释放一块内存。

参考程序:

#include #include int main( )

{

37

char *str;

/*为字符串申请分配一块内存*/ if((str=(char *)malloc(10))==NULL)

{printf(―Not enough memory to allocate buffer\\n‖); exit(1); /*若失败则结束程序*/ }

/*拷贝字符串“Hello”到已分配的内存空间*/ Strcpy(str,“Hello”); /*显示该字符串*/

printf(―string is %s\\n‖,str); /*内存使用完毕,释放*/ free(str); return 0; }

运行结果: String is Hello

(2)在上述实验的基础上重新分配内存。 参考程序:

#include #include int main( )

{

char *str;

/*为字符串申请分配一块内存*/ if((str=(char *)malloc(10))==NULL)

{printf(―Not enough memory to allocate buffer\\n‖); exit(1); /*若失败则结束程序*/ }

/*拷贝字符串“Hello”到已分配的内存空间*/ Strcpy(str,“Hello”);

/*显示该字符串和其所在的地址*/

printf(―string is %s\\n Address is %p\\n‖,str,str);

/*重新分配刚才申请到的内存空间,使空间增大一倍*/ if((str=(char*)realloc(str,20))==NULL) {printf(―Not enough memory to allocate buffer\\n‖); exit(1); /*若失败则结束程序*/ } /*显示重新分配后的地址*/

printf(‖String is %s\\n New address is %p/n‖,str,str); /*内存使用完毕,释放*/ free(str); return 0; }

运行结果: String is Hello

Address is 0x80498d0

38

String is Hello

New address is 0x80498d0

(3)使用自动分配内存函数分配内存。 参考程序:

#include #include void test(int a) {

char *newstack;

/*申请一块内存空间*/

newstack=(char*)alloca(a); if(newstack)

/*若成功,则输出空间大小和其起始地址*/

printf(―Alloca (0x%X) returned %p\\n‖,a,newstack); else

/*失败则报告错误*/

printf(―Alloca (0x%X) failed\\n‖,a);

} /*函数退出,内存自动释放,无需干预*/

void main( )

{

/*申请一块256字节大小的内存空间,观察输出情况*/ test(256);

/*再申请一块更大的内存空间,观察输出情况*/ test(16384); }

运行结果:

Alloca (0x100) returned 0xbfffd900 Alloca (0x400) returned 0xbfff9a00

实验四 文件管理

3、实验内容 (1)利用用户自定义的缓冲区,使对文件的单字节读/写操作在缓冲区中进行,只有当用户缓冲区空或满时,才调用read/write从(或“向”)文件读、写数据。 #include #include #include

#include #include #include #define SIZ 5 void rd();

39

void wr();

char buffer[SIZ]=”\\0”; int nread=0; int fd;

int main(int argc,char**argv) {

int rw;

if(argc<2){

fprintf(stderr,”illegal operation”); exit(EXIT_FAILURE);}

if(!strcmp(“read”,argv[1])) { rw=1;

printf(“[read mode]\\n”);} else{

if(!strcmp(“write”,argv[1])) { rw=0;

printf(“[write mode]\\n”);} }

switch(rw){ case 0: wr(); break; case 1: rd(); break; default: break;} exit(0); }

void rd() {

if(fd=open(“text”,O_RDONLY))==-1 { fprintf(stderr,”file open error\\n”); exit(EXIT_FAILURE);}

while((nread=read(fd,buffer,SIZ))!=0) { write(1,buffer,nread); } close(fd); }

void wr() {

40

while(nread

buffer[nread++]=getc(stdin); if(nread>SIZ)

printf(“buffer overrun”);} if((write(1,buffer,nread))!=nread)

write(2,”A write error has occurred\\n”,27); if((fd=open(“text”,O_WRONLY))==-1) { fprintf(stderr,”file open error\\n”); exit(EXIT_FAILURE);} else

write(fd,buffer,SIZ); close(fd); }

(2)设计一交互工具,使用该工具可以查看文件的状态信息;改变文件的模式、访问时间;显示目录文件内容并在其中执行任意的shell命令。 #include #include #include #include #include #include #define MAXSIZE 64

int main(int argc,char*argv[]) {

char option;

char command[MAXSIZE],attribute[MAXSIZE]; struct stat buf; struct tm time; if(argc>1) {

printf(“1) List file attribute\\n”); printf(“2) Modify file attribute\\n”); printf(“3) Modifed last access time\\n”); printf(“4) Enter shell command\\n”); printf(“Enter choice:”); option=getc(stdin);

switch(option) {

case ‘1’:if((stat(argv[1],&buf))==-1)

{printf(“Error getting file status?”);}

41

printf(“\\nFile Status of file %s\\n”,argv[1]); printf(“device:%0x\\n”,(dev_t)buf.st_dev); printf(“inode:%d\\n”,(ino_t)buf.st_ino );

printf(“protection:%d\\n”,(mode_t)buf.st_mode); printf(“number of hard links:%d\\n”,(nlink_t)buf.st_nlink); printf(“user ID of owner:%d\\n”,(uid_t)buf.st_uid); printf(“group ID of owner:%d\\n”,(gid_t)buf.st_gid); printf(“device type:%0x\\n”,(dev_t)buf.st_rdev);

printf(“total size,in bytes:%d\\n”,(off_t)buf.st_size); printf(“blocksize for system:%ld\\n”,(unsigned long)buf.st_blksize); printf(“number of blocks allocated:%ld\\n”,(unsigned long)buf.st_blocks);

printf(“time of last access:%ld\\n”,(time_t)buf.st_atime);

printf(“time of last modification:%ld\\n”,(time_t)buf.st_mtime); printf(“time of last change:%ld\\n\\n”,(time_t)buf.st_ctime); break;

case’2’:printf(“Enter new attribute eg:755(for rwxr-xr-x):”); scanf(“%s”,attribute); strcpy(command,”chmod”); strcat(command,attribute); strcat(command,””); strcat(command,argv[1]); system(command); break;

case’3’:utime(argv[1],NULL);

if((stat(argv[1],&buf))==-1)

{ printf(“Error getting file status?”);}

printf(“New access time is:%d”,(time_t)buf.st_atime); break;

case’4’:printf(“Enter any shell command to apply to file eg:ls/cat:”); scanf(“%s”,attribute);

strcat(command,attribute); strcat(command,””); strcat(command,argv[1]); system(command); break;

default:printf(“Invalid Option:Usage:tool\\n”); break; } } else

{ printf(“Usage:tool\\n”);} return(0) }

42

实验五 综合实验

2、实验内容

编程实现多个用户同时提交打印请求,并按序打印用户要求的文件。 要求:该实例主要包括两大部分

(1)sched守护进程,负责接受用户的打印请求并打印用户文件。 (2)lpp命令,用户用lpp命令提交打印请求。 提示:

43

本文来源:https://www.bwwdw.com/article/qper.html

Top