列出一个目录中的所有文件
ls1.c
#include "apue.h"
#include <stdio.h>
#include <dirent.h>
int main(int argc, char *argv[])
{
DIR *dp;
struct dirent *dirp;
if(argc != 2)
err_quit("usage: ls directory_name");
if((dp = opendir(argv[1])) == NULL)
err_sys("can't open %s", argv[1]); /* 自定义 */
while((dirp = readdir(dp)) != NULL)
printf("%s\n", dirp->d_name);
closedir(dp);
return 0;
}
将标准输入复制到标准输出
shell1.c
#include "apue.h"
#define BUFFSIZE 4096
int main(void)
{
int n;
char buf[BUFFSIZE];
/*
<unistd.h> 包含了STDIN_FILENO和STDOUT_FILENO
分别为标准输入、标准输出文件描述符
read 返回读得的字节数
wirte 返回写得的字节数
*/
while((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
if(write(STDOUT_FILENO, buf, n) != n)
err_sys("write error");
if(n < 0)
err_sys("read error");
exit(0);
}
停止输入时为Ctr+D
用标准I/O将标准输入复制到标准输出
shell2.c
不用选取缓冲区大小
#include "apue.h"
int main(void)
{
int c;
while((c = getc(stdin)) != EOF)
if(putc(c, stdout) == EOF)
err_sys("output error");
if(ferror(stdin))
err_sys("input error");
exit(0);
}
打印进程ID
hello.c
#include "apue.h"
int main(void)
{
printf("hello world from process ID %d\n", getpid());
exit(0);
}
从标准输入读入命令并执行
shell3.c
不能向命令传递参数
#include "apue.h"
#include <sys/wait.h>
int main(void)
{
char buf[MAXLINE]; /* from apue.h */
pid_t pid;
int status;
printf("%% "); /* 提示符,以区别于shell的提示符 */
while(fgets(buf, MAXLINE, stdin) != NULL)
{
if(buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = 0; /* execlp要求参数以null结束 */
if((pid = fork()) < 0)
err_sys("fork, error");
else if(pid == 0) /* child */
{
/*
execlp执行从标准输入读入的命令。用新的程序替换了子进程原先执行的程序。
*/
execlp(buf, buf, (char *)0);
err_ret("couldn't execute: %s", buf);
exit(127);
}
/* parent */
if((pid == waitpid(pid, &status, 0)) < 0)
err_sys("waitpid error");
printf("%% ");
}
exit(0);
}
打印用户ID和组ID
uidgid.c
#include "apue.h"
int main(void)
{
/*
root: 用户ID为0
组ID:同组成员之间可共享资源
*/
printf("uid = %d, gid = %d\n", getuid(), getgid());
exit(0);
}
从标准输入读入命令并执行
shell4.c
信号是通知进程发生某种情况的一种技术
终端键盘上两种产生信号的方式:
中断键:Ctrl + C
退出键: Ctrl + \
捕捉中断键信号,只是打印一条消息
#include "apue.h"
#include <sys/wait.h>
static void sig_int(int); /* out signal-catching function */
int main(void)
{
char buf[MAXLINE]; /* from apue.h */
pid_t pid;
int status;
if(signal(SIGINT, sig_int) == SIG_ERR)
err_sys("signal error");
printf("%% ");
while(fgets(buf, MAXLINE, stdin) != NULL)
{
if(buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = 0;
if((pid = fork()) < 0)
{
err_sys("fork error");
}
else if(pid == 0)
{
execlp(buf, buf, (char *)0);
err_ret("couldn't execute: %s", buf);
exit(127);
}
/* parent */
if((pid = waitpid(pid, &status, 0)) < 0)
err_sys("waitpid error");
printf("%% ");
}
exit(0);
}
void sig_int(int signo)
{
printf("interruput\n%%");
}
系统调用和库函数
库函数可替换,系统调用不可替换
内核中的系统调用sbrk分配另外一块空格给进程,而库函数malloc则在用户层次管理这一空间
系统调用通常提供一种最小接口,而库函数通常提供较为复杂的功能
Makefile
ROOT = ..
# 执行apue.3e/systype.sh
PLATFORM = $(shell $(ROOT)/systype.sh)
# 引入基本量
include $(ROOT)/Make.defines.$(PLATFORM)
PROGS = ls1 shell1 shell2 hello shell3 testerror uidgid shell4
# 目标all, 即运行make后所要达到的最终结果
all: $(PROGS)
# 执行gcc命令,相应的量的值在Make.defines.xxx文件中,@表示依赖文件
# CC:C编译器。默认是cc
# CFLAGS:C编译器选项。make会将这个选项作为参数,在将.c文件变成.o的阶段传给编译器
# LDFLAGS:类似CFLAGS,不过它是在将.o变成可执行程序的阶段传给连接器。
# LDLIBS:如果你用了LDFLAGS,但不想库名选项与查找路径混在一起,可以将库名选项写在这里。
%: %.c $(LIBAPUE)
$(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS) $(LDLIBS)
clean:
rm -f $(PROGS) $(TEMPFILES) *.O
# 引入apue.3e/Make.libapue.inc文件
include $(ROOT)/Make.libapue.inc