Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 27

Linux 内核与程序设计实验指导

实验一 实验名称:常用命令和编辑器的使用(2 学时)


一、实验目的
1、掌握 Linux 一般命令格式
2、掌握有关文件和目录操作的常用命令
3、掌握有关进程操作的常用命令
4、熟悉使用 man 命令
5、学习使用 vi 编辑器的建立、编辑、显示及加工处理文本文件
二、实验内容
1、熟悉 date、cal、who、echo、clear、passwd 命令
2、在用户主目录下对文件进行操作:复制一个文件、显示文件内容、查找指定内容、排
序、文件比较、文件删除等
3、对目录进行管理:创建和删除子目录、改变和现实工作目录、列出和更改文件权限、链
接文件等
4、利用 man 显示 date、echo 等命令的手册页
5、利用文本插入方式建立一个文件
6、对该文件执行删除、复原、修改、替换等操作
三、主要实验步骤
1、使用简单命令 date、cal、who、echo、clear、passwd 等,了解 linux 命令格式
输入 date 会显示当前日期
输入 cal 会显示日历
who:显示用户
clear 清屏
passwd 更换用户密码
2、浏览文件系统:
(1)运行 pwd 命令,确定当前工作目录
pwd:输出当前目录
(3)运行 ls –ai 命令,理解各字段含义
ls :列出当前目录下的文件和文件夹,不包括隐藏文件
ls -l:显示当前目录下文件或者文件夹的详细信息
ls -a:列出当前目录下的文件和文件夹,包括隐藏文件
ls -i:列出当前目录下的文件和文件夹,并显示其 index
ls -ai:列出当前目录下的文件和文件夹,包括隐藏文件,并显示其 index
(4)使用 cd 命令,将工作目录改为根(/)上,运行 ls –l 命令,结合书中图 2.2,了解个目录的作用
(5)/表示根目录
cd /即可
(5)直接使用 cd,回到哪里了?用 pwd 验证
/home/ysk,即用户目录
(6)用 mkdir 建立一个子目录 subdir 创建子目录:mkdir subdir
7)将工作目录改到 subdir
在 /home/ysk 下输入命令 cd subdir 定位为 /home/ysk/subdir
3、工作操作
(1) 验证当前工作目录在 subdir cat file1 是将 file1 文件中的内容显示到屏幕上
2) 运行 date>file1,然后运行 cat file1,看到什么信息? date>file1 是将当前时间输出入道 file1

3) 运行 cat subdir,会有什么结果?为什么? at: subdir: Is a directory
(4) 利用 man 命令显示 date 命令的使用说明 man date

4、运行 man date>>file1,看到什么? 追加进入 file1


运行 cat file1,看到什么?显示 file1 内的内容
5.文件操作
(1)显示 file1 的前 10 行,后 10 行 head -10 file1 tail -10 file1
(2)运行 cp file file2,然后 ls –l,看到什么 凭空多出了 file2,内容与 file 完全相同
(3)运行 cat f*,结果怎样 输出 f 开头文件的内容
(4)运行 rm file3,然后 ls –l,结果如何 rm 为删除命令
(5)统计 file1 文件的行数、字数 cat file1|wc -l
6.vi 编辑器
(1)进入 vi
(2)建立一个文件,如 file.c.进入插入方式,输入一个 C 语言程序的各行内容,故意制造几处
错误.最后,将该文件存盘.回到 shell 状态下.
(3)运行 gcc file.c –o myfile,编译文件,会发现错误提示.理解其含义
(4)重新进入 vi,对该文件进行修改.然后存盘,退出 vi.重新编译该文件.如果编译通过了,可以
用./myfile 运行该程序
(5)运行 mandate>file10,然后 vi file10。
使用 x,dd 等命令删除某些文本行。使用 u 命令复原此前的情况。
使用 c、r、s 等命令修改文本内容。使用检索命令进行给定模式的检索。
在 vi 编辑器中调大字体 ctrl+shift+'+ 在 vi 编辑器中减小字体 ctrl+'-'
linux 退出 vi 编辑器的方法
对于 vi 编辑器而言,输入 i 是插入状态。
如果要退出的话,先按 esc 键,然后输入冒号(:),
再输入 wq 是保存且退出,输入 q!不保存退出。
在某个一行按 数字+yy 可以复制指定数字的行,然后按 p 粘贴
u 撤销 ctrl+r 恢复上一步的操作
实验运行截图:
·
实验二 实验名称:shell 脚本的设计和执行(2 学时)

一、实验目的
1. 了解 shell 的作用和主要分类
2. 掌握 shell 脚本的建立和执行方式
3. 掌握编写 shell 脚本的基本语法
4. 学会编写并执行 shell 脚本
二、实验内容
1. 历史命令和别名定义
2. shell 脚本的建立和执行
3. shell 变量和位置参数、环境变量
4. shell 特殊字符在脚本中的使用
5. 一般控制结构的使用
6. 算数运算和函数的使用
三、主要实验步骤
1. 利用 vi 编辑器建立一个简单的 shell 脚本,其中包括 date,pwd,ls 等常用命令。然后以至
少两种不同的方式执行该脚本(参考书上 P84,4.1.3 节内容)。
echo hello,world
echo "hello,world2"
实验结果:hello,world
hello,world2
2. 运行 history 命令,查看历史命令环境;
3. [cyf@localhost ~]$ history
3. 体会命令补齐功能(参见 4.3 节内容);
[cyf@192 ~]$ cat ex
ex ex11~ ex14 ex2 ex4 exam12~ exp1
ex~ ex12 ex17 ex2~ ex4~ exam13
ex11 ex13 ex17~ ex3 exam12 exam13~
[cyf@192 ~]$ cat ex
按下 tab+tab 或者 esc+ '?'
4. 编辑并运行书上 P91 页 4.5.2 节引号的相关脚本和命令;
[ysk@192 ~]$ cat ex
echo "current directory is `pwd`"
echo "home directory is $HOME"
echo "file*.?"
echo "directory ‘$HOME’ "
echo directory ‘$HOME’
[cyf@192 ~]$ ./ex
current directory is /home/cyf
home directory is /home/cyf
file*.?
directory ‘/home/cyf’
directory ‘/home/cyf’
[cyf@192 ~]$
5. 编辑并运行书上 P108 页例 4.9,体会位置参数的相关用法;
echo $0 $1 $2 $3 $4 $5 $6 $7 $8 $9 shift
echo $0 $1 $2 $3 $4 $5 $6 $7 $8 $9
shift 4
echo $0 $1 $2 $3 $4 $5 $6 $7 $8 $9

[cyf@localhost ~]$ ./cyf_1 A B C D E F G H I J K


./cyf_1 A B C D E F G H I
./cyf_1 B C D E F G H I J
./cyf_1 F G H I J K
6. 编辑并运行书上 P125 页,例 4.13,体会 shell 脚本中条件表达式、算数表达式、逻辑运
算的使用方法,同时需要注意实验室 linux 环境与书本中 linux 版本的不一致;
cyf_2:
f [ 3 -gt 2 ]
Then
echo "3>2"
else
echo "3<=2"
fi
[cyf@localhost ~]$ ./cyf_2
3>2
if [[ 3 -gt 2 ]]
then
echo "3>2"
else
echo "3<=2"
fi
[cyf@localhost ~]$ ./cyf_2
3>2

f [ 3 -lt 2 -o 3 -gt 2 ]
then
echo "true"
else
echo "false"
fi

[cyf@localhost ~]$ ./cyf_2


true

不能把里面的-o 写成||
否则结果是 false
7. 编辑并运行书上 P130 页,例 4.15,体会值表方式的 for 循环与位置参数相结合的使用方
法;
dir=$1;shift
if [ -d $dir ]
then
cd $dir
for name
do
if [ -f $name ]
then cat $name
echo "End of ${dir}/$name"
else
echo "Invalid file name: ${dir}/$name"
fi
done
else echo "Bad directory name:$dir"
fi
[cyf@192 ~]$ ./ex144 code 111 222
#echo "sa"
echo "sa"
End of code/111
if test -f "$1"
then echo "$1 is a file"
else echo "$1 is not a file"
fi
End of code/222
[cyf@192 ~]$
if 和[之间需要有空格
8. 编辑并运行书上 P131 页,例 4.16,体会算数表达式方式的 for 循环用法;
for((i=1;i<=$1;i++))
do
for((j=1;j<=i;j++))
do
echo -n "*"
done
echo ""
done
echo "end!"
[cyf@192 ~]$ ./ex145 4
运行结果
*
**
***
****
end!
[cyf@192 ~]$
9. 编辑并运行书上 P134 页,例 4.19,体会 shell 脚本中函数的使用;
10.自己编写 shell 脚本,实现以下功能:
Shell 脚本文件名为 sq,执行时接受 2-10 范围内的一个整数作为输入参数,在屏幕上用+
号、@号和 &号画出以给定参数为边长的正方形。
&特殊字符 echo 时需要加引号" "或' '
例如:输入命令$ sq 4 并回车,则屏幕上会绘制如下的正方形,(注:其中第 2、3 行上的
&符号之间有两个空格)
@++@
& &
& &
@++@
read x
if [ $x -lt 2 -o $x -gt 10 ]
then
echo "x must in [2,10]"
exit
fi
echo -n @
for((i=1;i<=$x-2;i++))
do
echo -n +
done
echo @
for((i=1;i<=$x-2; i++))
do
echo -n '&'
for((j=1;j<=$x-2;j++))
do
echo -n " "
done
echo "&"
done
echo -n @
for((i=1;i<=$x-2;i++))
do
echo -n +
done
echo @
[cyf@192 ~]$ ./t2_10
4
@++@
& &
& &
@++@

实验截图:

实验三 实验名称: Linux 环境下程序的编译和调试(2 学时)


一、实验目的
1、 掌握 gcc 编译器在预处理、编译、汇编和连接各个阶段的用法
2、 掌握 gdb 调试工具的常用命令
二、实验内容
1. 使用 gcc 编译器中的预处理选项
2. 使用 gcc 编译器中的编译程序选项
3. 使用 gdb 调试工具的使用
三、实验步骤

1. 编写并验证书本 P180 页例题 6.1

hello.c
#include<testI.h>
#define fatal "!!!!!!"
main()
{
printf("display -D variable %s\n",DOPTION);
printf("display overwrite fatal=%s\n",fatal);
printf("Hello ,everybody!!\n");
}

testI.h
#define fatal "please call Lawrence for help"

[cyf@localhost ~]$ gcc -I ./tmp -D DOPTION='"testing -D" ' -D fatal -E hello.c


# 1 "hello.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "hello.c"
# 1 "./tmp/testI.h" 1
In file included from hello.c:1:
./tmp/testI.h:1:1: warning: "fatal" redefined
<command-line>: warning: this is the location of the previous definition
# 2 "hello.c" 2
hello.c:2:1: warning: "fatal" redefined
./tmp/testI.h:1:1: warning: this is the location of the previous definition
main()
{
printf("display -D variable %s\n","testing -D");
printf("display overwrite fatal=%s\n","!!!!!!");
printf("Hello ,everybody!!\n");
}
[cyf@localhost ~]$
出现了重复的宏定义,如果都没有相关的定义那么 -D fatal 后 fatal 的值为 1
//#include<testI.h>
#define fatal "please call Lawrence for help"
main()
{
printf("display -D variable %s\n","testing -D");
printf("display overwrite fatal=%s\n","please call Lawrence for help");
printf("Hello ,everybody!!\n");
}
控制台:
[cyf@localhost ~]$ gcc -D DOPTION=' "testing -D"' hello.c
hello.c: In function ‘main’:
hello.c:7: warning: incompatible implicit declaration of built-in function ‘printf’
[cyf@localhost ~]$ ./a.out
display -D variable testing -D
display overwrite fatal=please call Lawrence for help
Hello ,everybody!!
[cyf@localhost ~]$ gcc -D DOPTION=' "testing -D"' hello.c
hello.c: In function ‘main’:
hello.c:7: warning: incompatible implicit declaration of built-in function ‘printf’
[cyf@localhost ~]$ ./a.out
display -D variable testing -D
display overwrite fatal=please call Lawrence for help
Hello ,everybody!!
2. 编写并验证书本 P181 页例题 6.2
#include <stdio.h>
in
int r;
printf("Enter an integer,please!\n");
scanf("%d",&r);
square(r);
return 0;
}
#include<stdio.h>
int square(int x)
{ printf("The square=%d\n",x*x);
return 0;
}

[cyf@localhost ~]$ gcc -c meng2.c


[cyf@localhost ~]$ gcc meng1.o meng2.o -o meng12
[cyf@localhost ~]$ ./meng12
Enter an integer,please!
2
The square=4
3. 编写并验证书本 P193 页 6.2.6 应用示例
实验截图:
实验四 实验名称:Linux 进程控制程序的设计和实现(2 学时)

一、实验目的
1、 理解系统调用和库函数的使用方法和格式
2、 掌握文件操作相关的系统调用函数的使用和编程
3、 掌握进程控制相关的系统调用函数的原理、语法和编程应用
二、实验内容
1. 使用文件操作系统调用函数 open,read,write 进行程序设计
2. 创建子进程的系统调用 fork()设计程序,观察程序的执行结果
3. 比较子进程等待函数 wait 和 waitpid 的异同
三、实验步骤
1.编辑并运行下列代码,理解 fork 函数的执行原理
int main()
{ int i;
int pid;
pid=fork();
if (pid<0) printf(“error”)
else if (pid == 0)
{ for (i = 1; i < 3; i++)
printf("This is child process\n");
}
else
{ for (i = 1; i < 3; i++)
printf("This is parent process\n");}

}
#include<stdio.h>
int main()
{
int i;
int pid;
pid=fork();
if (pid<0) printf("error");
else if (pid == 0)
{
for (i = 1; i < 3; i++)
printf("This is child process\n");
}
else
{
for (i = 1; i < 3; i++)
printf("This is parent process\n");
}
return 0;
}
2.编辑并执行下列程序,观察并分析程序执行结果
int com=0;
main()
{
pid_t pid;
pid=fork();

if(pid<0)
then printf("error");
else if(pid==0)
then
{com=1};
else
{com=com+1};

printf{"com=%d\n",com};
}
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int com=0;
int main()
{
pid_t pid;
pid=fork();

if(pid<0) printf("error");
else if(pid==0) com=1;
else com=com+1;

printf("com=%d\n",com);

return 0;
}

3.编辑并执行下列程序,观察并分析进程 ID 获取函数的用法
#include <unistd.h>
#include <sys/types.h>
main()
{
pid_t pid;
pid=fork();
if(pid<0) printf("fork error!\t");
else if(pid==0)
printf("child process now! pid=%d ppid=%d\t",getpid(),getppid());

elseprintf("parent process now! pid=%d child_pid=%d\t",getpid(),pid);


}

#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
int main()
{
pid_t pid;
pid=fork();
if(pid<0) printf("fork error!\n");
else if(pid==0)
printf("child process now! pid=%d ppid=%d\n",getpid(),getppid());

else
printf("parent process now! pid=%d child_pid=%d\n",getpid(),pid);
return 0;
}

因为用 fork 函数创建子进程,父进程没有等待子进程的退出,这可能导致子进程编程孤儿


进程,被 init 进程接管,所以父进程 id 为 1

4. 编写程序验证书本 P213 页的例题 7.3


#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>

int main(int argc,char **argv)


{
pid_t pid,old_ppid,new_ppid;
pid_t child,parent;

parent=getpid();
if((child=fork())<0)
{

fprintf(stderr,"%s:fork of child failed:%s\n",argv[0],strerror(errno) );


exit(1);
}
else if(child==0)
{
old_ppid=getppid();
sleep(2);
new_ppid=getppid();
}
else
{
sleep(1);
exit(0);
}

printf("Original parent:%d\n",parent);
printf("Child:%d\n",getpid());
printf("Child's old ppid:%d\n",old_ppid);
printf("Child's new ppid:%d\n",new_ppid);
exit(0);
}

5.编写程序验证 PPT 中的相关例题,思考运行结果。

实验截图:
实验五 实验名称:Linux 进程通信的程序设计和实现(2 学时)

一、实验目的

1、 掌握进程通信相关的系统调用的语法格式
2、 掌握 pipe,kill 和消息队列函数在父子进程通信时的具体用法
3、 能够读、写系统调用程序,理解程序的输出结果。

二、实验内容
1. 在程序设计中使用 pipe 函数进行基于管道的进程通信
2. 在程序设计中使用 kill 函数进行基于信号量的进行通信
3. 在程序设计中使用消息队列机制实现进行通信
三、实验步骤
1.参考下列伪码,编辑并执行 pipe 函数的程序

#include<unistd.h>
#include<stdio.h>
#include<errno.h>
int main(intargc,char **argv)
{

static const char mesg[]="Happy NewYear";


char buf[BUFSIZ];
size_t rcount,wcount;
int p_fd[2];
size_t n;
if(pipe(p_fd)<0){

printf(“pipe error”);
exit(EXIT_FAILURE);
}
printf("Read end=fd %d,write end=fd%d\n",p_fd[0],p_fd[1]);
n=strlen(mesg);
if((wcount=write(p_fd[1],mesg,n))!=n){
printf(“write error”);
exit(EXIT_FAILURE);
}
if((rcount=read(p_fd[0],buf,BUFSIZ))!=wcount){
printf(“read error”);
exit(EXIT_FAILURE);
}
printf("Read <%s>from pipe\n",buf);
close(p_fd[0]);
close(p_fd[1]);
return 0;
}

#include<unistd.h>
#include<stdio.h>
#include<errno.h>
#include<stdlib.h>
#include<string.h>
int main(int argc,char **argv)
{
static const char mesg[]="Happy NewYear";
char buf[BUFSIZ];
size_t rcount,wcount;
int p_fd[2];
size_t n;
if(pipe(p_fd)<0){

printf("pipe error");

exit(EXIT_FAILURE);

printf("Read end=fd %d,write end=fd %d\n",p_fd[0],p_fd[1]);

n=strlen(mesg);

if((wcount=write(p_fd[1],mesg,n))!=n){

printf("write error");

exit(EXIT_FAILURE);

if((rcount=read(p_fd[0],buf,BUFSIZ))!=wcount){

printf("read error");

exit(EXIT_FAILURE);

printf("Read <%s>from pipe\n",buf);


close(p_fd[0]);

close(p_fd[1]);

return 0;

2.在下列伪码中加入头文件,编辑运行,理解 kill 函数

int main()

{ pid_tchild;

int status, retval;

if((child=fork())<0) {perror(“fork”); exit(EXIT_FAILURE); }

else if (child==0) {

printf(“Child’s ID:%d\n”, child);

sleep(20);

exit(0); }

else {

if((waitpid(child,&status,WNOHANG))==0){

retval=kill(child,SIGKILL);

if (retval){

perror(“kill”);

waitpid(child,&status,0);

else printf(“%d iskilled”,child);

}
#include<unistd.h>
#include<stdio.h>
#include<errno.h>
#include<stdlib.h>
#include<string.h>
#include<signal.h>

int main()
{
pid_t child;
int status, retval;

if((child=fork())<0)
{
perror("fork"); exit(EXIT_FAILURE);
}
else if (child==0)
{
printf("Child's ID:%d\n", child);
sleep(20);
exit(0);
}
else
{

if( (waitpid(child,&status,WNOHANG) )==0)


{
retval=kill(child,SIGKILL);
if (retval)
{
perror("kill");

waitpid(child,&status,0);
}
else printf("%d is killed\n",child);
}

return 0;
}
3.编辑并运行书本 P218 页进程使用消息队列进行通信的例题。思考消息队列的使用机制
和运作机制。
#include<unistd.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<stdio.h>//5
#include<stdlib.h>
#include<string.h>
#define BUFSZ 512
struct msg
{//10
long type;
char text[BUFSZ];
};

int main(void)//15
{
int qid;
key_t key;
int len1,len2;
struct msg pmsg_w,pmsg_r;//20

key=IPC_PRIVATE;
if( (qid=msgget(key,IPC_CREAT|0666 ) )<0 )
{
perror("msgget:create");//25
exit(EXIT_FAILURE);
}
puts("Enter message to past");
if(fgets(pmsg_w.text,BUFSZ,stdin)==NULL)
{//30
puts("Wrong,no message to post.");
exit(EXIT_FAILURE);
}
pmsg_w.type=10;
len1=strlen(pmsg_w.text);//35
if(msgsnd(qid,&pmsg_w,len1,IPC_NOWAIT )<0)
{
perror("msgsnd");
exit(EXIT_FAILURE);
}//40
puts("message posted.");
puts("***************");

len2=msgrcv(qid,&pmsg_r,BUFSZ,10,IPC_NOWAIT|MSG_NOERROR);
if(len2>0)//45
{
pmsg_r.text[len2]='\0';
printf("reading queue id=%05d\n",qid);
printf("message type=%05ld\n",pmsg_r.type);
printf("message length=%d bytes\n",len2);//50
printf("message text=%s\n",pmsg_r.text);
}
else
{
perror("msgrcv");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
4.编辑并运行书本 P220 页例题 7.7, 思考和验证运行结果。
#include<unistd.h>
#include<sys/types.h>
#include<wait.h>
#include<signal.h>
#include<stdio.h>//5
#include<stdlib.h>

int main()
{
pid_t pid;//10
int num;
if( (pid=fork())<0 )
{
perror("fork");
exit(EXIT_FAILURE);//15
}
else if(pid==0)
{
sleep(30);
}//20
else
{
printf("Sending SIGCHLD to %d\n",pid);
num=kill(pid,SIGCHLD);
if(num<0)//25
perror("kill:SIGCHLD");
else
printf("%d still alive\n",pid);
printf("Killing %d\n",pid);
if( (kill(pid,SIGTERM) )<0 )
perror("kill:SIGTERM");
waitpid(pid,NULL,0);

}
exit(EXIT_SUCCESS);
}
5.编写程序验证 PPT 中的相关例题,思考运行结果。
实验截图:

You might also like