[Linux] [阅读] [APUE] - 第一章 UNIX基础知识

本文通过多个C语言程序实例,展示了如何使用系统调用进行文件操作、标准输入输出、进程管理和信号处理等基本功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

程序清单1-1:列出指定目录中所有文件的名字,即命令ls的简要实现

#include "apue.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);
    exit(0);
}

编译生成ls1文件,运行:

# ./ls1 ..   // 列出上一级目录中的所有文件

  • The opendir function returns a pointer to a DIR structure, and we pass this pointer to the readdir function. We don't care what's in the DIR structure. We then call readdir in a loop, to read each directory entry. The readdir function returns a pointer to a dirent structure or, when it's finished with the directory, a null pointer. All we examine in the dirent structure is the name of each directory entry (d_name). Using this name, we could then call the stat function (Section 4.2) to determine all the attributes of the file.

 

程序清单1-2:将标准输入复制到标准输出

#include "apue.h"

#define BUFFSIZE    4096

int
main(void)
{
    int     n;
    char    buf[BUFFSIZE];

    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);
}

编译生成a.out文件,并以如下方式运行它:

#./a.out >data  //标准输入时终端,标准输出则重定向至文件data,标准出错也是终端。如果此输出文件不存在,则shell会创建它。该程序将用户键入的各行复制到标准输出,键入文件结束字符时(通常是ctrl+D),则终止该次复制。

#./a.out < infile > outfile //将名为infile文件的内容复制到名为outfile的文件中。

The constants STDIN_FILENO and STDOUT_FILENO are defined in <unistd.h> and specify the file descriptors for standard input and standard output. These values are typically 0 and 1, respectively, but we'll use the new names for portability.

 

程序清单1-3:用标准I/O将标准输入复制到标准输出

#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);
}

The function getc reads one character at a time, and this character is written by putc. After the last byte of input has been read, getc returns the constant EOF (defined in <stdio.h>). The standard I/O constants stdin and stdout are also defined in the <stdio.h> header and refer to the standard input and standard output.

程序清单1-4:打印进程ID

#include "apue.h"

int
main(void)
{
    printf("hello world from process ID %d\n", getpid());
    exit(0);
}

程序清单1-5:从标准输入读命令并执行

#include "apue.h"
#include <sys/wait.h>

int
main(void)
{
    char    buf[MAXLINE];   /* from apue.h */
    pid_t   pid;
    int     status;

    printf("%% ");  /* print prompt (printf requires %% to print %) */
    while (fgets(buf, MAXLINE, stdin) != NULL) {
        if (buf[strlen(buf) - 1] == "\n")
            buf[strlen(buf) - 1] = 0; /* replace newline with null */

        if ((pid = fork()) < 0) {
            err_sys("fork error");
        } else if (pid == 0) {      /* child */
            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);
}

If we run this program, we get the following results. Note that our program has a different promptthe percent signto distinguish it from the shell's prompt.

   $ ./a.out
   % date
   Sun Aug 1 03:04:47 EDT 2004            programmers work late
   % who
   sar     :0       Jul 26 22:54
   sar     pts/0    Jul 26 22:54 (:0)
   sar     pts/1    Jul 26 22:54 (:0)
   sar     pts/2    Jul 26 22:54 (:0)
   % pwd
   /home/sar/bk/apue/2e
   % ls
   Makefile
   a.out
   shell1.c
   % ^D                                   type the end-of-file character
   $                                      the regular shell prompt
  • The most fundamental limitation of this program is that we can't pass arguments to the command that we execute.

程序清单1-6:示例strerror和perror

#include "apue.h"
#include <errno.h>

int
main(int argc, char *argv[])
{
    fprintf(stderr, "EACCES: %s\n", strerror(EACCES));
    errno = ENOENT;
    perror(argv[0]);
    exit(0);
}

If this program is compiled into the file a.out, we have

   $ ./a.out
   EACCES: Permission denied
   ./a.out: No such file or directory

There are two rules to be aware of with respect to errno. First, its value is never cleared by a routine if an error does not occur. Therefore, we should examine its value only when the return value from a function indicates that an error occurred. Second, the value of errno is never set to 0 by any of the functions, and none of the constants defined in <errno.h> has a value of 0.

Two functions are defined by the C standard to help with printing error messages.

 

 

#include <string.h>

char *strerror(int errnum);
 

 

Returns: pointer to message string

 

This function maps errnum, which is typically the errno value, into an error message string and returns a pointer to the string.

The perror function produces an error message on the standard error, based on the current value of errno, and returns.

 

 

#include <stdio.h>

void perror(const char *msg);
 

 

 

It outputs the string pointed to by msg, followed by a colon and a space, followed by the error message corresponding to the value of errno, followed by a newline.

程序清单1-7:打印用户ID和组ID

#include "apue.h"

int
main(void)
{
    printf("uid = %d, gid = %d\n", getuid(), getgid());
    exit(0);
}

We call the functions getuid and getgid to return the user ID and the group ID. Running the program yields

   $ ./a.out
   uid = 205, gid = 105

程序清单1-8:从标准输入读命令并执行

// + 为相对于程序清单1-5新增的代码行

  #include "apue.h"
  #include <sys/wait.h>

+ static void sig_int(int);       /* our 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("%% ");  /* print prompt (printf requires %% to print %) */
      while (fgets(buf, MAXLINE, stdin) != NULL) {
          if (buf[strlen(buf) - 1] == "\n")
              buf[strlen(buf) - 1] = 0; /* replace newline with null */

          if ((pid = fork()) < 0) {
              err_sys("fork error");
          } else if (pid == 0) {        /* child */
              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("interrupt\n%% ");
+ }

To catch this signal, the program needs to call the signal function, specifying the name of the function to call when the SIGINT signal is generated. The function is named sig_int; when it's called, it just prints a message and a new prompt.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值