sleep

  1. #include "kernel/types.h"
  2. #include "user/user.h"
  3. int main(int argc, char *argv[])
  4. {
  5. if (argc != 2)
  6. {
  7. fprintf(2, "error input\n");
  8. exit(1);
  9. }
  10. int sec = atoi(argv[1]);
  11. sleep(sec);
  12. exit(0);
  13. }

pingpong

  1. #include <kernel/types.h>
  2. #include <user/user.h>
  3. int main(){
  4. //pipe1(p1):写端父进程,读端子进程
  5. //pipe2(p2);写端子进程,读端父进程
  6. int p1[2],p2[2];
  7. //来回传输的字符数组:一个字节
  8. char buffer[] = {'X'};
  9. //传输字符数组的长度
  10. long length = sizeof(buffer);
  11. //父进程写,子进程读的pipe
  12. pipe(p1);
  13. //子进程写,父进程读的pipe
  14. pipe(p2);
  15. //子进程
  16. if(fork() == 0){
  17. //关掉不用的p1[1]、p2[0]
  18. close(p1[1]);
  19. close(p2[0]);
  20. //子进程从pipe1的读端,读取字符数组
  21. if(read(p1[0], buffer, length) != length){
  22. printf("a--->b read error!");
  23. exit(1);
  24. }
  25. //打印读取到的字符数组
  26. printf("%d: received ping\n", getpid());
  27. //子进程向pipe2的写端,写入字符数组
  28. if(write(p2[1], buffer, length) != length){
  29. printf("a<---b write error!");
  30. exit(1);
  31. }
  32. exit(0);
  33. }
  34. //关掉不用的p1[0]、p2[1]
  35. close(p1[0]);
  36. close(p2[1]);
  37. //父进程向pipe1的写端,写入字符数组
  38. if(write(p1[1], buffer, length) != length){
  39. printf("a--->b write error!");
  40. exit(1);
  41. }
  42. //父进程从pipe2的读端,读取字符数组
  43. if(read(p2[0], buffer, length) != length){
  44. printf("a<---b read error!");
  45. exit(1);
  46. }
  47. //打印读取的字符数组
  48. printf("%d: received pong\n", getpid());
  49. //等待进程子退出
  50. wait(0);
  51. exit(0);
  52. }

primes

  1. #include <kernel/types.h>
  2. #include <user/user.h>
  3. void child_pro(int p[]) {
  4. int x,y;
  5. // 用于与子进程通信的管道
  6. int child_p[2];
  7. // 从父进程读取,所以关闭与父进程连接管道的写入端
  8. close(p[1]);
  9. // 从父进程读取成功之后的逻辑
  10. if (read(p[0],&x,sizeof(int))) {
  11. // 打印读取成功后的素数
  12. // 上一层中传递的第一个值一定是素数,并且依据这个值筛选素数
  13. fprintf(1,"prime %d\n",x);
  14. // 创建与子进程通信的管道
  15. pipe(child_p);
  16. // 再次使用fork,当自身为父进程时
  17. if (fork() != 0) {
  18. // 关闭与子进程通信的读取端
  19. close(child_p[0]);
  20. // 从父进程持续读取,读取的数字不为第一个数字的倍数时,持续向子进程写入
  21. while (read(p[0], &y, sizeof(int))) {
  22. if (y %x != 0) {
  23. write(child_p[1], &y, sizeof(int));
  24. }
  25. }
  26. // 关闭从父进程的读取
  27. close(p[0]);
  28. // 关闭向子进程的写入
  29. close(child_p[1]);
  30. // 等待子进程完成
  31. wait(0);
  32. }
  33. // 创建子进程
  34. else {
  35. child_pro(child_p);
  36. }
  37. }
  38. exit(0);
  39. }
  40. int main(){
  41. int p[2];
  42. pipe(p);
  43. if (fork()!=0) {
  44. close(p[0]);// 关闭第一个管道的读取
  45. for(int i = 2;i<=35;i++){
  46. write(p[1],&i,sizeof(int));
  47. }// 主进程,将2到35写入第一个管道
  48. close(p[1]);// 关闭第一个管道的写入
  49. wait(0);// 等待子进程完成
  50. exit(0);
  51. }
  52. else {
  53. child_pro(p);// 执行子进程
  54. }
  55. exit(0);
  56. }

find

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"

char* getfilename(char *path)
{
  char *p;

  //Find first character after last slash.
    // 从后向前遍历,找到并返回‘/’后的序列
  for(p=path+strlen(path); p >= path && *p != '/'; p--)
    ;
  p++;
  return p;
}
void find(char *path, char* target)
{
  char buf[512], *p;
  int fd;
    // 目录项结构体
  struct dirent de;
    // 文件统计信息
  struct stat st;
  // 当打开失败的时候,报错
  if((fd = open(path, 0)) < 0){
    fprintf(2, "find: cannot open %s\n", path);
    return;
  }
    //fstat()用来将参数fildes所指的文件状态,复制到参数buf所指的结构中(struct stat)执行成功则返回0,失败返回-1,错误代码存于errno
  if(fstat(fd, &st) < 0){
    fprintf(2, "find: cannot stat %s\n", path);
    close(fd);
    return;
  }
    //判断打开的类型
  switch(st.type){
  // 打开的是文件
  case T_FILE:
          // 打开的文件与目标匹配,输出
    if (strcmp(getfilename(path), target) == 0) {
      printf("%s\n", path);
    }
    break;
          // 打开的是路径
  case T_DIR:
          // 判断是否溢出
    if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){
      printf("find: path too long\n");
      break;
    }
          // 把path拷贝到buf里
    strcpy(buf, path);
          // 指向buf的末尾
    p = buf+strlen(buf);
    *p++ = '/';
          // 每次读取一个目录
    while(read(fd, &de, sizeof(de)) == sizeof(de)){
        // 文件夹下无文件
      if(de.inum == 0) {
          // 进行下一次读取
        continue;
      }
      if (strcmp(de.name, ".") == 0 || strcmp(de.name, "..") == 0) { // 跳过子目录的.和..
        continue;
      }
        // 将de.name中的内容移动到p指针所指向的位置,拼接路径字符串
      memmove(p, de.name, DIRSIZ);
      p[DIRSIZ] = 0;
      if(stat(buf, &st) < 0){
        printf("find: cannot stat %s\n", buf);
        continue;
      }
      find(buf, target);
    }
    break;
  }
  close(fd);
}
int main(int argc, char *argv[])
{
  // 两个参数,起始路径和目标文件
  if(argc < 3){
    fprintf(2, "find: need 2 args\n");
    exit(1);
  }
  find(argv[1], argv[2]);
  exit(0);
}

xargs

  1. shell中的 ‘|‘ 是将标准输出转换为标准输入
  2. linux中的xargs命令是将标准输入转换为shell命令行参数(http://www.ruanyifeng.com/blog/2019/08/xargs-tutorial.html)
  3. exec(filename,params),其中param的第一个参数为命令名称,最后一个参数是0image.png
  4. 命令行一行最长4095bytes ```c

    include “kernel/types.h”

    include “kernel/stat.h”

    include “user/user.h”

    include “kernel/param.h”

int main(int argc, char argv[]) { // 遍历buf,确认读取结束 int buf_idx, read_len; char buf[512]; char exe_argv[MAXARG]; // 跳过存储“xargs”的argv[0] for (int i = 1; i < argc; i++) { exe_argv[i-1] = argv[i]; } while (1) { buf_idx = -1; do { buf_idx++; // 读取并存储到buf中直到换行或到达结尾 read_len = read(0, &buf[buf_idx], sizeof(char)); } while (read_len > 0 && buf[buf_idx] != ‘\n’); // 读到结尾,跳出循环 if (read_len ==0 && buf_idx == 0) { break; } buf[buf_idx] = ‘\0’; exe_argv[argc - 1] = buf;

    if (fork()==0) {
        exec(exe_argv[0], exe_argv);
        exit(0);
    }
    else {
        wait(0);
    }
}

exit(0); } ```