Professional Documents
Culture Documents
Linux内核与程序设计实验指导
Linux内核与程序设计实验指导
一、实验目的
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
f [ 3 -lt 2 -o 3 -gt 2 ]
then
echo "true"
else
echo "false"
fi
不能把里面的-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
@++@
& &
& &
@++@
实验截图:
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"
一、实验目的
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());
#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;
}
parent=getpid();
if((child=fork())<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);
}
实验截图:
实验五 实验名称: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)
{
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);
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);
close(p_fd[1]);
return 0;
2.在下列伪码中加入头文件,编辑运行,理解 kill 函数
int main()
{ pid_tchild;
else if (child==0) {
sleep(20);
exit(0); }
else {
if((waitpid(child,&status,WNOHANG))==0){
retval=kill(child,SIGKILL);
if (retval){
perror(“kill”);
waitpid(child,&status,0);
}
#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
{
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 中的相关例题,思考运行结果。
实验截图: