当前位置: 首页 > news >正文

深入了解linux系统—— 自定义shell

shell的原理

我们知道,我们程序启动时创建的进程,它的父进程都是bash也就是shell命令行解释器;

bash都做了哪些工作呢?

根据已有的知识,我们可以简单理解为:

  1. 输出命令行提示符
  2. 获取并解析我们输入的指令
  3. 执行内建命令或者创建子进程执行命令

在这里插入图片描述

就如下图所示,bash读取我们输入的命令,并进行解析;然后创建子进程执行命令(bash等待子进程退出)。

在这里插入图片描述

自定义shell实现

根据上述bash的工作原理,我们现在实现一个简单的自定义shell

要想实现一个自定义shell,我们就要执行以下过程:

  • 获取命令行
  • 解析命令行
  • 创建子进程,让子进程执行命令(使用程序替换)
  • shell等待子进程退出

当然,还存在一部分内建命令,它是由bash自主实现的;我们要进行特殊处理;

1. 输出命令行提示符

在实现自定义shell之前,我们来看

在这里插入图片描述

我们的bash在每次都会输出命令行提示符,然后等待我们用户输入;

看这个命令行提示符,它包含以下信息:

  • 用户名USER
  • 主机名HOSTNAME
  • 当前工作路径PWD

这些在我们的环境变量表中都能够找到,所以我们就可以使用getenv来获取。

在这里插入图片描述

所以这个就非常容易实现了,直接按照格式输出即可;

这样我们需要获取环境变量USERHOSTNAMEPWD等;

但是我们会发现bash输出的命令行提示符中的当前工作路径只有当前文件,而我们通过环境变量PWD获取的是当前工作目录的绝对路径,所以我们这里要进行一下分割;

详细代码如下:

//命令行提示符格式
#define CLP "[%s@%s %s]#"
//命令行提示符的最大长度
#define MAX_CLP 100
//获取环境变量
const char* GetUser(){return getenv("USER");
}
const char* GetHostName(){return getenv("HOSTNAME");
}
const char* GetPwd()
{return getenv("PWD");
}
//分割路径
//"/home/lxb/linux/MYSHELL" --> "MYSHELL"
string DirPwd(char s[])
{
#define SLASH "/"string str = s;if(str == SLASH) return str;                                                                       auto pos = str.rfind(SLASH);if(pos == std::string::npos) return "err";return str.substr(pos+1);
}         
//生成命令行提示符
void CommandLinePrompt(char buffer[])
{sprintf(buffer,CLP,GetUser(),GetHostName(),DirPwd(GetPwd());
}
//输出命令行提示符
void PrintCommandPrompt()
{char buffer[100];CommandLinePrompt(buffer);printf("%s",buffer);fflush(stdout);
}

在这里插入图片描述

2. 获取用户输入的信息

输出了命令行提示符,接下来就要获取用户输入的信息了,也就是输入的命令;

在这里插入图片描述

在用户输入时,是会输入空格的,所以这里我们不能使用scanf/cin进行输入;我们要使用fgets进行输入。

而也可能存在只输入一个回车的情况,所以我们要进行特殊判断:当只输入一个回车时就再次输出命令行提示符,然后等待用户输入。

输入:

//命令行信息最大长度    
#define MAX_COMLINE 1024
char* GetCommandLine(char buff[]){char* c = fgets(buff,MAX_COMLINE,stdin);buff[strlen(buff)-1] = 0;//处理回车return c;
}

这里来测试一下输出命令行提示符和获取用户输入信息;

如果获取用户输入信息成功,那就输出获取的输入信息,如果失败或者只输入了一个回车就再次输出命令行提示符,然后等待用户输入。

int main()
{while(1){//1. 输出命令行提示符PrintCommandPrompt();//2. 获取用户输入信息char buff[MAX_COMLINE];char* c = GetCommandLine(buff);if(c == NULL)//读取用户输入信息失败continue;if(strlen(buff) == 0)//只输入了空格continue;printf("%s\n",buff);}return 0;
}

在这里插入图片描述

3. 命令行解析

获取了用户输入的信息,但是我们获得的是一个字符串,而我们要想执行用户输入的命令,要先对这个字符串进行解析;生成对应的命令行参数表,才能够去执行。

命令行参数个数g_argc,命令行参数表g_argv;我们可以设置成全局的,这样每次通过修改argcargv中最后一个指针为NULL即可。

这里,我们可以使用strtok函数进行分割命令行参数;

简单描述一下strtok,在str字符串中查找sep字符串的内容,找到并将其修改成\0并返回指向这个字符串的指针。

在这里插入图片描述

在分割完成之后,我们直接让g_argv命令行参数表指向对应位置即可。

在这里插入图片描述

#define MAX_ARGC 50
//命令行参数表
int g_argc;
char* g_argv[MAX_ARGC];
//解析命令行参数                                                               
//"ls -a -l"--> "ls" "-a" "-l"                                                      
void PrasCommandLine(char buff[]){                                  g_argc = 0;                                          const char* sep = " ";      for(g_argv[g_argc] = strtok(buff,sep);g_argv[g_argc] != NULL; g_argv[g_argc] = strtok(NULL,sep))    g_argc++;    
}   

这里还是测试,命令行解析是否成功。

在这里插入图片描述

4. 创建子进程执行命令

解析命令行,生成命令行参数表之后,现在就是去执行命令了;

我们的shell并不是自己去执行,而是创建子进程,然后让子进程去执行命令,shell等待子进程退出。

void CreateChildExecute(){    int id = fork();    if(id < 0)    {    perror("fork");    exit(1);    }    else if (id == 0){    //child    execvp(g_argv[0],g_argv);    exit(2);    }    //parent    wait(NULL);    
}

这里我们使用的程序替换函数是execvp,我们有命令行参数表(数组),而且我们输入的系统命令是不带路径的;

看一下运行效果:

在这里插入图片描述

扩展部分

在上述描述中,简单的shell运行就OK了;

但是上述我们没有考虑内建命令环境变量表等这些东西;

环境变量表

bash启动时,它的环境变量表从我们系统的配置文件中来,但是我们这里没办法从系统配置文件中读;所以我们这里就只能从父进程bash获取环境变量表;

这里即从bash中获取环境变量;

但是拿到了环境变量表,进程中还是保存的来自父进程bash的环境变量;environ还是执行bash的环境变量表。

我们需要导出环境变量,使用putenv来导出环境变量;然后让environ执行我们的环境遍历表。

//环境变量表最大数量
#define MAX_GENV 500
int g_argc;
char* g_argv[MAX_GARGC];
//环境变量表
int g_envs;    
char* g_env[MAX_GENV];    
//导入环境变量    
void EnvInit(){      extern char** environ;    memset(g_env,0,sizeof(g_env));    g_envs = 0;                              //环境变量表要从系统文件中来             //这从bash中获取    for(int i = 0;environ[i]!=NULL;i++){    g_env[i] = (char*) malloc(strlen(environ[i])+1);    if(g_env[i] == NULL){    perror("malloc");    exit(3);    }    strcpy(g_env[i], environ[i]);    g_envs++;    }    g_env[g_envs] = NULL;    //导出环境变量    for(int i = 0;i < g_envs;i++){    putenv(g_env[i]);    }    environ = g_env;                                                                                                                                                                              
}

在我们程序启动时,从父进程bash获取环境变量即可。

内建命令

内建命令,指bash不创建子进程去执行,而是bash自己去执行的命令;

我们现在知道内建命令有cdexportecho等。

cd

cd命令,仔细想一想,肯定不会是子进程执行的;因为子进程执行它修改的是子进程的工作路径。

我们要让shell去执行cd命令,肯定不能使用程序替换了,我们可以使用chdir系统调用来修改当前工作路径;

在这里插入图片描述

cd命令:

  1. cd:会进入用户的家目录
  2. cd ~:进入用户的家目录
  3. cd where:进入指定路径
  4. cd -:进入上次的工作路径
void CD(){std::string oldpwd = getenv("PWD");std::string where;if(g_argc == 1){where = GetHome();if(where.empty()) return;chdir(where.c_str());                                                                                                                                                                     }else{where = g_argv[1];if(strcmp("-", g_argv[1]) == 0){where = getenv("OLDPWD");}else if(strcmp("~", g_argv[1]) == 0){where = GetHome();if(where.empty()) return;}chdir(where.c_str());//修改环境变量}
}

当然呢,这里存在一个问题,当我们cd -进入上次各种目录时就会发现,它进入的一直都是同一个目录;

因为我们这里没有修改环境变量OLDPWD

echo

echo命令也是内建命令,我们知道,echo $?可以查看最近一次进程退出时的退出码;

但是在我们的shell中,如果让子进程去执行echo $?,它则是直接输出$?

在这里插入图片描述

echo $?,查看最近一次进程退出时的退出码;而这些退出码在哪里呢?

肯定不会在子进程中,那就在bash中了;

所以在我们的shell中,我们可以定义一个全局变量,每次执行一次命令就对其进行一次修改。

//最近一次进程退出时的退出码
int last_code;
void Echo(){                                                      if(g_argc == 2){    std::string str = g_argv[1];    if(str == "$?"){    std::cout<<last_code<<std::endl;    }    else if(str[1] == '$'){    std::string env_name = str.substr(1);    const char* s = getenv(env_name.c_str());    if(s)    std::cout<<s<<std::endl;    }    else{    std::cout<<str<<std::endl;    }    }    
}    

这里,设置了last_code,那在每次执行命令之后,都要进行更新last_code

除此之外呢,还有非常多的内建命令,比如exportunset等;这里就不实现了。

别名alias

如果测试我们可以发现,bash支持ll,而我们的shell是不支持的;

我们知道ll是别名,所以如果想要我们shell支持别名,我们就要在shell中新增一张别名表;

然后维护这张别名表,就可以支持ll等指令的别名了。

这里就不实现了,可以使用unordered_map或者map来存储这张别名表。

到这里本篇文章大致内容就结束了;

本篇文章自定义实现shell,帮助理解进程,以及bash是如何工作的

附源码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <cstdbool>
#include <sys/types.h>
#include <sys/wait.h>
#include <string>
//命令行提示符格式
#define CLP "[%s@%s %s]# "
#define MAX_CLP 100
//命令行信息最大长度
#define MAX_COMLINE 1024
//命令行参数最大个数
#define MAX_GARGC 50
//环境变量表最大数量
#define MAX_GENV 500
int g_argc;
char* g_argv[MAX_GARGC];
//环境变量表
int g_envs;
char* g_env[MAX_GENV];
//最近一次进程退出时的退出码
int last_code = 0;
//导入环境变量
void EnvInit(){extern char** environ;memset(g_env,0,sizeof(g_env));g_envs = 0;//环境变量表要从系统文件中来                                                                                                                                                                  //这从bash中获取for(int i = 0;environ[i]!=NULL;i++){g_env[i] = (char*) malloc(strlen(environ[i])+1);if(g_env[i] == NULL){perror("malloc");exit(3);}strcpy(g_env[i], environ[i]);g_envs++;                                                                                                                                                                                 }g_env[g_envs] = NULL;//导出环境变量for(int i = 0;i < g_envs;i++){putenv(g_env[i]);}environ = g_env;
}
//获取环境变量
char* GetUser(){return getenv("USER");
}
char* GetHostName(){return getenv("HOSTNAME");
}
//路径切割
std::string DirPwd(const char s[])
{
#define SLASH "/"std::string str = s;if(str == SLASH) return str;auto pos = str.rfind(SLASH);if(pos == std::string::npos) return "err";return str.substr(pos+1);
}
const char* GetPwd()
{//return getenv("PWD");return DirPwd(getenv("PWD")).c_str();
}
const char* GetHome(){return getenv("HOME");                                                  
}
//生成命令行提示符
void CommandLinePrompt(char buffer[])
{sprintf(buffer,CLP,GetUser(),GetHostName(),GetPwd());//sprintf(buffer,CLP,GetUser(),GetHostName(),DirPwd(GetPwd()).c_str());
}
void PrintCommandPrompt()
{char buffer[100];CommandLinePrompt(buffer);printf("%s",buffer);fflush(stdout);
}
char* GetCommandLine(char buff[]){char* c = fgets(buff,MAX_COMLINE,stdin);buff[strlen(buff)-1] = 0;return c;
}
void PrasCommandLine(char* buff){g_argc = 0;const char* sep = " ";for(g_argv[g_argc] = strtok(buff,sep); g_argv[g_argc] != NULL; g_argv[g_argc] = strtok(NULL,sep)){g_argc++;}
}
void CreateChildExecute(){int id = fork();if(id < 0){perror("fork");exit(1);                                                                                                                                                                                  }else if (id == 0){//childexecvp(g_argv[0],g_argv);exit(2);}//parentint status = 0;int rid = wait(&status);if(rid > 0)last_code = WEXITSTATUS(status);
}
void Cd(){std::string oldpwd = getenv("PWD");std::string where;if(g_argc == 1){where = GetHome();if(where.empty()) return;                                                                                                                                                                 chdir(where.c_str());}else{where = g_argv[1];if(strcmp("-", g_argv[1]) == 0){where = getenv("OLDPWD");}else if(strcmp("~", g_argv[1]) == 0){where = GetHome();if(where.empty()) return;}chdir(where.c_str());//修改环境变量}//std::string old = std::string("OLDPWD=") + oldpwd;//char* arr = (char*)malloc(old.size()+1);//for(size_t i = 0;i<old.size();i++){//    arr[i] = old[i];//}//arr[old.size()] = 0;//putenv(arr);
}
void Echo(){if(g_argc == 2){                                                                                                                                                                              std::string str = g_argv[1];if(str == "$?"){std::cout<<last_code<<std::endl;}else if(str[1] == '$'){std::string env_name = str.substr(1);const char* s = getenv(env_name.c_str());if(s)std::cout<<s<<std::endl;}else{std::cout<<str<<std::endl;}}
}
//判断内建命令
bool BinCommand(){std::string str = g_argv[0];if(str == "cd"){Cd();last_code = 0;return true;}else if(str == "echo"){Echo();last_code = 0;return true;}return false;            
}
void PrintArgv(){for(int i = 0;i < g_argc; i++){printf("g_argv[%d] : %s\n",i,g_argv[i]);}
}
void PrintEnv(){for(int i = 0; i < g_envs;i++){printf("g_env[%d] : %s\n",i,g_env[i]);}
}
int main()
{//获取环境变量表EnvInit();//PrintEnv();while(1){                                                                                                                                                                                     //1. 输出命令行提示符PrintCommandPrompt();//2. 获取用户输入信息char buff[MAX_COMLINE];char* c = GetCommandLine(buff);if(c == NULL)//读取用户输入信息失败continue;if(strlen(buff) == 0)//只输入了空格continue;//3. 命令行解析PrasCommandLine(buff);//4.内建命令if(BinCommand())continue;//5. 创建子进程执行命令CreateChildExecute();}return 0;
}

相关文章:

深入了解linux系统—— 自定义shell

shell的原理 我们知道&#xff0c;我们程序启动时创建的进程&#xff0c;它的父进程都是bash也就是shell命令行解释器&#xff1b; 那bash都做了哪些工作呢&#xff1f; 根据已有的知识&#xff0c;我们可以简单理解为&#xff1a; 输出命令行提示符获取并解析我们输入的指令…...

【通讯录教程】如何将号码快速导入手机通讯录,支持苹果和安卓手机,一次性导入大量号码进入手机通讯录,基于WPF的解决方案

以下是一个基于WPF的解决方案&#xff0c;用于将大量号码快速导入苹果和安卓手机通讯录&#xff1a; 项目应用场景 ​​企业员工通讯录批量导入​​&#xff1a;HR需要将数百名员工的联系方式快速导入公司手机​​客户关系管理​​&#xff1a;销售人员需要将大量客户信息导入…...

Git初始化相关配置

Git配置 在Git安装完成后&#xff0c;windows操作系统上会多出一个Git Bash的软件&#xff0c;如果是linux或者是macOS&#xff0c;那么直接打开终端&#xff0c;在终端中敲击命令即可 # 检查git版本 git -v # 或 git --version在使用git时&#xff0c;需要配置一下用户名和邮…...

n8n中订阅MQTT数据

第一步&#xff1a;创建mqtt登录证证 第二步&#xff1a;创建mqtt trigger组件&#xff0c;并配置凭证和订阅主题 第三步&#xff1a;创建Code节点&#xff0c;编写格式转换代码 第四步&#xff1a;创建转发MQTT节点&#xff0c;并配置MQTT凭证 第五步&#xff1a;启用工作流 整…...

Docker、ECS 与 K8s 网段冲突:解决跨服务通信中的路由问题

&#x1f9e9; 问题背景 在阿里云的项目中&#xff0c;在项目初期搭建过程中遇到了一个让人头疼的网络冲突问题&#xff1a;同一个 VPC 中的 Docker 容器和 Kubernetes 集群由于使用相同的网段&#xff0c;导致k8s pod连接ECS容器之间的网络连接失败。 背景环境&#xff1a; …...

《智能网联汽车 自动驾驶系统设计运行条件》 GB/T 45312-2025——解读

目录 1. 标准概述 2. 核心概念 3. 标准核心内容 3.1 一般要求 3.2 ODC基础元素层级 3.3 ODC元素具体要求 3.4 附录A&#xff08;ODC示例&#xff09; 4. 技术挑战与实施建议 5. 标准意义 原文链接&#xff1a;国家标准|GB/T 45312-2025 &#xff08;发布&#xff1a;2…...

AARRR用户增长模型(海盗指标)详解

目录 一、模型起源与概述二、五大阶段详解1. 获取&#xff08;Acquisition&#xff09;1.1 定义1.2 关键指标 2. 激活&#xff08;Activation&#xff09;2.1 定义2.2 关键指标 3. 留存&#xff08;Retention&#xff09;3.1 定义3.2 关键指标3.3 提升留存手段案例3.4 互联网留…...

CSS专题之自定义属性

前言 石匠敲击石头的第 12 次 CSS 自定义属性是现代 CSS 的一个强大特性&#xff0c;可以说是前端开发需知、必会的知识点&#xff0c;本篇文章就来好好梳理一下&#xff0c;如果哪里写的有问题欢迎指出。 什么是 CSS 自定义属性 CSS 自定义属性英文全称是 CSS Custom Proper…...

JVM——Java字节码基础

引入 Java字节码&#xff08;Java Bytecode&#xff09;是Java技术体系的核心枢纽&#xff0c;所有Java源码经过编译器处理后&#xff0c;最终都会转化为.class文件中的字节码指令。这些指令不依赖于具体的硬件架构和操作系统&#xff0c;而是由Java虚拟机&#xff08;JVM&…...

【React中useRef钩子详解】

一、useRef的核心特性 useRef是React提供的Hook,用于在函数组件中创建可变的持久化引用,具有以下核心特性: 持久化存储 返回的ref对象在组件整个生命周期内保持不变,即使组件重新渲染,current属性的值也不会丢失。无触发渲染 修改ref.current的值不会导致组件重新渲染,适…...

《AI大模型应知应会100篇》第58篇:Semantic Kernel:微软的大模型应用框架

第58篇&#xff1a;Semantic Kernel&#xff1a;微软的大模型应用框架 ——用C#和Python构建下一代AI应用的统一编程范式 &#x1f4cc; 摘要 随着大模型&#xff08;LLM&#xff09;技术的快速发展&#xff0c;如何将这些强大的语言模型与传统代码系统进行无缝集成&#xff…...

ssh -T git@github.com 测试失败解决方案:修改hosts文件

问题描述 通过SSH方式测试&#xff0c;使用该方法测试连接可能会遇到连接超时、端口占用的情况&#xff0c;原因是因为DNS配置及其解析的问题 ssh -T gitgithub.com我们可以详细看看建立 ssh 连接的过程中发生了什么&#xff0c;可以使用 ssh -v命令&#xff0c;-v表示 verbo…...

c++面向对象:接口设计

一、什么是接口&#xff08;Interface&#xff09;&#xff1f; 在面向对象编程中&#xff0c;接口可以理解为一种“规范”或“约定”。 更具体一点&#xff1a; 它定义了“某个对象”应该具备哪些功能&#xff08;方法、行为&#xff09;但不关心这些功能的具体实现细节 用…...

[Java][Leetcode middle] 80. 删除有序数组中的重复项 II

删除重复元素&#xff0c;最多只保留两个 1. 计数法 第一个元素直接加入当与前一个元素相同时&#xff0c;计数器1&#xff0c;不同时计数器恢复1&#xff1b; 只有计数器小于2时&#xff0c;记录元素&#xff1b; public int removeDuplicates2(int[] nums) {int cnt 1;in…...

【Bluedroid】蓝牙HID DEVICE断开连接流程源码分析

蓝牙HID&#xff08;Human Interface Device&#xff09;的断开连接流程涉及从应用层到协议栈的多层交互。本文通过剖析Android Bluetooth协议栈代码&#xff0c;梳理从上层调用disconnect()到最终物理链路断开的完整流程&#xff0c;涵盖状态检查、消息传递、L2CAP通道关闭、资…...

嵌入式硬件篇---陀螺仪|PID

文章目录 前言1. 硬件准备主控芯片陀螺仪模块电机驱动电源其他 2. 硬件连接3. 软件实现步骤(1) MPU6050初始化与数据读取(2) 姿态解算&#xff08;互补滤波或DMP&#xff09;(3) PID控制器设计(4) 麦克纳姆轮协同控制 4. 主程序逻辑5. 关键优化与调试技巧(1) 传感器校准(2) PID…...

redis数据结构-07(SADD、SREM、SMEMBERS)

Redis Sets 简介&#xff1a;SADD、SREM、SMEMBERS Redis 集合是一种基础数据结构&#xff0c;可用于存储一组唯一且无序的元素。了解如何管理集合对于各种应用至关重要&#xff0c;从跟踪唯一访客到管理用户权限。本课将全面介绍 Redis 集合&#xff0c;重点介绍核心命令 SAD…...

嵌入式硬件篇---TOF|PID

文章目录 前言1. 硬件准备主控芯片ToF模块1.VL53L0X2.TFmini 执行机构&#xff1a;电机舵机其他 2. 硬件连接(1) VL53L0X&#xff08;IC接口&#xff09;(2) TFmini&#xff08;串口通信&#xff09; 3. ToF模块初始化与数据读取(1) VL53L0X&#xff08;基于HAL库&#xff09;(…...

# Anaconda3 常用命令

Anaconda3 常用命令及沙箱环境管理指南 Anaconda3 是一个强大的 Python 发行版&#xff0c;广泛用于数据科学、机器学习和科学计算。其核心优势在于通过 沙箱环境&#xff08;Conda Environment&#xff09; 实现项目隔离&#xff0c;避免依赖冲突。本文将介绍 Anaconda3 的常…...

嵌入式硬件篇---无线通信模块

文章目录 前言一、四种无线串口模块深度对比二、模块优缺点分析1. 蓝牙模块&#xff08;HC-05&#xff09;优点缺点 2. WiFi模块&#xff08;ESP8266&#xff09;优点缺点 3. 2.4G射频&#xff08;NRF24L01&#xff09;优点缺点 4. LoRa模块&#xff08;SX1278&#xff09;优点…...

MySQL 索引(二)

文章目录 索引理解MySQL对page做管理page的概念单个page多个page 页目录单页情况&#xff08;提高page内部的查找的效率&#xff09;多页情况&#xff08;提高page间的查找效率&#xff09;复盘一下为什么选择B树&#xff0c;不选择其他数据结构呢聚簇索引 VS 非聚簇索引 索引操…...

代码随想录算法训练营第六十天| 图论7—卡码网53. 寻宝

图论第七天&#xff0c;prim和kruskal算法&#xff0c;说实话都没看的很懂&#xff0c;有点抽象难理解&#xff0c;只能照着题解理解一下了。 53. 寻宝&#xff08;prim&#xff09; 53. 寻宝&#xff08;第七期模拟笔试&#xff09; 复制一下网站上的prim算法的结论 prim算…...

「OC」源码学习—— 消息发送、动态方法解析和消息转发

「OC」源码学习—— 消息发送、动态方法解析和消息转发 前言 前面我们在学习alloc源码的时候&#xff0c;就在callAlloc源码之中简单的探究过&#xff0c;类初始化缓存的问题&#xff0c;我们知道在一个类第一次被实例化的时候&#xff0c;会调用objc_msgSend去二次调用alloc…...

MySQL数据库下篇

#作者&#xff1a;允砸儿 #日期&#xff1a;乙巳青蛇年 四月十四 今天笔者将会把MySQL数据库的知识完结&#xff0c;再者笔者会浅写一下sql注入的内容。在后面笔者会逐渐的将网安世界徐徐展开。 php与mysql联动 编程接口 笔者在前面的文章写了php的内容&#xff0c;现在我…...

Linux之进程概念

目录 一、冯诺依曼体系结构 二、操作系统(Operator System) 2.1、概念 2.2、设计OS的目的 2.3、系统调用和库函数概念 三、进程 3.1、基本概念 3.1.1、描述进程-PCB 3.1.2、task_struct 3.1.3、查看进程 3.1.4、通过系统调用获取进程标识符 3.1.5、两种杀掉进程的方…...

numpy模块综合使用

一、numpy模块的综合使用方法 # 使用矩阵的好处&#xff0c;矩阵对于python中列表&#xff0c;字典等数据类型一个一个拿来计算是会方便计算很多的&#xff0c;底层使用的是c语言 # 在数据分析和数据处理的时候也经常常用 import numpy as np array np.array([[1,2,3],[2,3,4…...

嵌入式硬件篇---SPI

文章目录 前言1. SPI协议基础1.1 物理层特性四线制&#xff08;标准SPI&#xff09;SCKMOSIMISONSS/CS 三线制&#xff08;半双工模式&#xff09;通信模式 1.2 通信时序&#xff08;时钟极性CPOL和相位CPHA&#xff09;常用模式Mode 0Mode 3 1.3 典型通信流程 2. STM32F103RCT…...

【大模型】AI智能体Coze 知识库从使用到实战详解

目录 一、前言 二、知识库介绍 2.1 coze 知识库功能介绍 2.2 coze 知识库应用场景 2.3 coze 知识库类型 2.4 coze 知识库权限说明 2.5 coze 知识库与记忆对比 2.6 知识库的使用流程 三、知识库创建与使用 3.1 创建知识库入口 3.2 创建文本知识库 3.2.1 上传文件 3.…...

深度学习:系统性学习策略(二)

深度学习的系统性学习策略 基于《认知觉醒》与《认知驱动》的核心方法论,结合深度学习的研究实践,从认知与技能双重维度总结以下系统性学习策略: 一、认知觉醒:构建深度学习的思维操作系统 三重脑区协同法则 遵循**本能脑(舒适区)-情绪脑(拉伸区)-理智脑(困难区)**的…...

TikTok 推广干货:AI 加持推广效能

TikTok 推广是提升账号影响力、吸引更多关注的关键一环。其中&#xff0c;巧妙利用热门话题标签是增加视频曝光的有效捷径。运营者需要密切关注当下流行趋势&#xff0c;搜索与账号定位紧密相关的热门标签。例如&#xff0c;对于美妆账号而言&#xff0c;带上 “# 美妆教程 #热…...

滑动窗口——将x减到0的最小操作数

题目&#xff1a; 这个题如果我们直接去思考方法是很困难的&#xff0c;因为我们不知道下一步是在数组的左还是右操作才能使其最小。正难则反&#xff0c;思考一下&#xff0c;无论是怎么样的&#xff0c;最终这个数组都会分成三个部分左中右&#xff0c;而左右的组合就是我们…...

无侵入式弹窗体验_探索 Chrome 的 Close Watcher API

1. 引言 在网页开发中,弹窗(Popup)是一种常见的交互方式,用于提示用户进行操作、确认信息或展示关键内容。然而,传统的 JavaScript 弹窗方法如 alert()、confirm() 和 prompt() 存在诸多问题,包括阻塞主线程、样式不可定制等。 为了解决这些问题,Chrome 浏览器引入了 …...

牛客周赛 Round 92 题解 Java

目录 A 小红的签到题 B 小红的模拟题 C 小红的方神题 D 小红的数学题 E 小红的 ds 题 F 小红的小苯题 A 小红的签到题 直接构造类似于 a_aaaa&#xff0c;a_aaaaaaaa 这种 即可 // github https://github.com/Dddddduo // github https://github.com/Dddddduo/acm-java…...

DAY 17 训练

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 DAY 17 训练 聚类算法聚类评估指标介绍1. 轮廓系数 (Silhouette Score)2. CH 指数 (Calinski-Harabasz Index)3. DB 指数 (Davies-Bouldin Index) 1. KMeans 聚类算法原理确定…...

多源最短路径(Floyed)

#include <iostream> #include <vector> #include <stack> using namespace std; class Graph{ private: int vertex; //顶点数 //int** matrix; //有向图关系矩阵 int** path; //存储关系矩阵 int** pre; //存储中间节点k public: con…...

基于去中心化与AI智能服务的web3钱包的应用开发的背景描述

Web3代表了下一代互联网模式&#xff0c;其核心特征包括去中心化、数据主权、智能合约和区块链技术的广泛应用。根据大数据调查显示&#xff0c;用户希望拥有自己的数据控制权&#xff0c;并希望在去中心化网络中享受类似Web2的便捷体验。DeFi(去中心化金融) 生态日趋成熟的背景…...

LabVIEW车牌自动识别系统

在智能交通快速发展的时代&#xff0c;车牌自动识别系统成为提升交通管理效率的关键技术。本案例详细介绍了基于 LabVIEW 平台&#xff0c;搭配大恒品牌相机构建的车牌自动识别系统&#xff0c;该系统在多个场景中发挥着重要作用&#xff0c;为交通管理提供了高效、精准的解决方…...

C# Newtonsoft.Json 使用指南

Newtonsoft.Json (也称为 Json.NET) 是一种适用于 .NET 的常用高性能 JSON 框架&#xff0c;用于处理 JSON 数据。它提供了高性能的 JSON 序列化和反序列化功能。 安装 通过 NuGet 安装 基本用法 1. 序列化对象为 JSON 字符串 using Newtonsoft.Json;var product new Prod…...

Python_day22

DAY 22 复习日 复习日 仔细回顾一下之前21天的内容&#xff0c;没跟上进度的同学补一下进度。 作业&#xff1a; 自行学习参考如何使用kaggle平台&#xff0c;写下使用注意点&#xff0c;并对下述比赛提交代码 kaggle泰坦里克号人员生还预测 一、Kaggle 基础使用步骤 注册与登录…...

浏览器的B/S架构和C/S架构

浏览器的B/S架构和C/S架构 概述拓展 欢迎来到 Shane 的博客~ 心有猛虎&#xff0c;细嗅蔷薇。 概述 C/S架构&#xff1f; Client/Server架构。但是缺少通用性、系统维护、升级需要重新设计和开发&#xff0c;并且需要开发不同的操作系统&#xff0c;增加了维护和管理的难度。&…...

【C++】内存管理 —— new 和 delete

文章目录 一、C/C 内存分布二、C 语言中动态内存管理方式1. malloc / calloc / realloc / free 三、C 内存管理方式1. new / delete2. operator new 与 operator delete 函数3. new 和 delete 的实现原理(1) new 的原理(2) delete 的原理(3) new T[N] 的原理(4) delete[] 的原理…...

springboot3整合SpringSecurity实现登录校验与权限认证

一&#xff1a;概述 1.1 基本概念 &#xff08;1&#xff09;认证 系统判断身份是否合法 &#xff08;2&#xff09;会话 为了避免每次操作都进行认证可将用户信息保存在会话中 session认证 服务端有个session&#xff0c;把 session id给前端&#xff0c;每次请求cookie都带着…...

【东枫科技】使用LabVIEW进行深度学习开发

文章目录 DeepLTK LabVIEW深度学习工具包LabVIEW中的深度神经网络**功能与特性****功能亮点&#xff1a;** **支持的网络层****支持的网络架构****参考示例** 授权售价 DeepLTK LabVIEW深度学习工具包 LabVIEW中的深度神经网络 功能亮点&#xff1a; 在 LabVIEW 中创建、配置…...

《智能网联汽车 自动驾驶系统通用技术要求》 GB/T 44721-2024——解读

目录 一、核心框架与适用范围 二、关键技术要求 1. 总体要求 2. 动态驾驶任务执行 3. 动态驾驶任务后援 4. 人机交互&#xff08;HMI&#xff09; 5. 说明书要求 三、附录重点 附录A&#xff08;规范性&#xff09;——功能安全与预期功能安全 附录B&#xff08;资料性…...

同一个虚拟环境中conda和pip安装的文件存储位置解析

文章目录 存储位置的基本区别conda安装的包pip安装的包 看似相同实则不同的机制实际路径示例这种差异带来的问题如何检查包安装来源最佳实践建议 总结 存储位置的基本区别 conda安装的包 存储在Anaconda(或Miniconda)目录下的pkgs和envs子目录中&#xff1a; ~/anaconda3/en…...

《Hadoop 权威指南》笔记

Hadoop 基础 MapReduce Hadoop 操作 Hadoop 相关开源项目...

每日一题洛谷P8615 [蓝桥杯 2014 国 C] 拼接平方数c++

P8615 [蓝桥杯 2014 国 C] 拼接平方数 - 洛谷 (luogu.com.cn) #include<iostream> #include<string> #include<cmath> using namespace std; bool jud(int p) {int m sqrt(p);return m * m p; } void solve(int n) {string t to_string(n);//int转换为str…...

【C++】AVL树实现

目录 前言 一、AVL树的概念 二、AVL树的实现 1.基本框架 2.AVL树的插入 三、旋转 1.右单旋 2.左单旋 3.左右双旋 4.右左双旋 四、AVL树的查找 五、AVL树的平衡检测 六、AVL树的删除 总结 前言 本文主要讲解AVL树的插入&#xff0c;AVL树是在二叉搜索树的基础上&a…...

49.EFT测试与静电测试环境和干扰特征分析

EFT测试与静电测试环境和干扰特征分析 1. EFT/B电快速瞬变脉冲群测试及干扰特征分析2. EFT的干扰特征分析与滤波方法3. ESD静电测试及干扰特征分析 1. EFT/B电快速瞬变脉冲群测试及干扰特征分析 EFT测试是模拟在大的感性设备断开瞬间产生的快速瞬变脉冲群对被测设备的影响。 E…...

html body 设置heigth 100%,body内元素设置margin-top出滚动条(margin 重叠问题)

今天在用移动端的时候发现个问题&#xff0c;html,body 设置 height&#xff1a;100% 会出现纵向滚动条 <!DOCTYPE html> <html> <head> <title>html5</title> <style> html, body {height: 100%; } * {margin: 0;padding: 0; } </sty…...