分布自定义shell脚本(详写)附带全代码
涉及知识全排列
常见指令
小知识点
操作系统
什么是进程
进程控制
步骤 1:项目准备
在开始编写代码之前,你需要创建一个新的项目文件夹,并在其中创建一个 .cpp
文件,例如 my_shell.cpp
。同时,确保你已经安装了 C++ 编译器(如 g++
),可以在终端中使用以下命令检查:
g++ --version
步骤 2:包含必要的头文件和定义宏
打开 my_shell.cpp
文件,在文件开头包含所需的头文件,并定义一些宏,这些宏将用于设置命令行大小和提示符格式。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unordered_map>#define COMMAND_SIZE 1024
#define FORMAT "[%s@%s %s]# "
-
头文件解释:
-
iostream
:用于标准输入输出流,方便进行信息的显示和获取用户输入。 -
cstdio
:提供标准输入输出函数,如printf
和fgets
。 -
cstring
:包含字符串处理函数,像strcpy
和strlen
。 -
cstdlib
:提供通用工具函数,如malloc
和exit
。 -
unistd.h
:包含许多 Unix 系统调用,如fork
、execvp
和chdir
。 -
sys/types.h
:定义了系统数据类型,在系统调用中经常用到。 -
sys/wait.h
:用于处理进程等待,如waitpid
函数。 -
unordered_map
:C++ 标准库中的哈希表容器,用于存储命令别名映射。
-
-
宏定义解释:
-
COMMAND_SIZE
:设置用户输入命令的最大长度为 1024 字节。 -
FORMAT
:定义命令行提示符的格式,会显示用户名、主机名和当前工作目录。
-
步骤 3:定义全局变量
在头文件和宏定义之后,定义一些全局变量,用于存储命令行参数、环境变量和命令别名等信息。
// 命令行参数表
#define MAXARGC 128
char *g_argv[MAXARGC];
int g_argc = 0;// 环境变量表
#define MAX_ENVS 100
char *g_env[MAX_ENVS];
int g_envs = 0;// 别名映射表
std::unordered_map<std::string, std::string> alias_list;// 当前工作目录相关
char cwd[1024];
char cwdenv[2048];// 上一次退出码
int lastcode = 0;
-
命令行参数:
-
MAXARGC
:最大命令行参数数量为 128。 -
g_argv
:存储命令行参数的指针数组。 -
g_argc
:记录命令行参数的实际数量。
-
-
环境变量:
-
MAX_ENVS
:最大环境变量数量为 100。 -
g_env
:存储环境变量的指针数组。 -
g_envs
:记录环境变量的实际数量。
-
-
别名映射表:
alias_list
是一个哈希表,用于存储命令别名和其对应的实际命令。 -
当前工作目录:
-
cwd
:存储当前工作目录的字符数组。 -
cwdenv
:存储PWD
环境变量的字符数组,大小为 2048 字节。
-
-
上一次退出码:
lastcode
保存上一个执行命令的退出状态码。
步骤 4:编写获取系统信息的函数
接下来,编写几个函数用于获取系统信息,如用户名、主机名、当前工作目录和用户主目录。
// 获取用户名
const char *GetUserName() {const char *name = getenv("USER");return name == nullptr ? "None" : name;
}// 获取主机名
const char *GetHostName() {const char *hostname = getenv("HOSTNAME");return hostname == nullptr ? "None" : hostname;
}// 获取当前工作目录
const char *GetPwd() {const char *pwd = getcwd(cwd, sizeof(cwd));if (pwd != nullptr) {size_t cwd_len = strlen(cwd);size_t prefix_len = strlen("PWD=");if (cwd_len + prefix_len + 1 <= sizeof(cwdenv)) {snprintf(cwdenv, sizeof(cwdenv), "PWD=%s", cwd);putenv(cwdenv);}}return pwd == nullptr ? "None" : pwd;
}// 获取用户主目录
const char *GetHome() {const char *home = getenv("HOME");return home == nullptr ? "" : home;
}
-
GetUserName
函数:使用getenv
函数获取USER
环境变量的值,如果获取不到则返回"None"
。 -
GetHostName
函数:使用getenv
函数获取HOSTNAME
环境变量的值,如果获取不到则返回"None"
。 -
GetPwd
函数:-
使用
getcwd
函数获取当前工作目录并存储到cwd
中。 -
检查
cwdenv
缓冲区是否足够大,如果足够则将PWD
环境变量的值设置为当前工作目录。 -
如果获取不到当前工作目录,则返回
"None"
。
-
-
GetHome
函数:使用getenv
函数获取HOME
环境变量的值,如果获取不到则返回空字符串。
步骤 5:编写初始化环境变量的函数
编写一个函数用于初始化环境变量,将系统环境变量复制到自定义的环境变量数组中,并添加一个测试用的环境变量。
// 初始化环境变量
void InitEnv() {extern char **environ;memset(g_env, 0, sizeof(g_env));g_envs = 0;// 从系统环境变量复制for (int i = 0; environ[i]; ++i) {g_env[i] = static_cast<char *>(malloc(strlen(environ[i]) + 1));strcpy(g_env[i], environ[i]);++g_envs;}g_env[g_envs++] = strdup("HAHA=for_test");g_env[g_envs] = nullptr;// 设置环境变量for (int i = 0; g_env[i]; ++i) {putenv(g_env[i]);}environ = g_env;
}
-
InitEnv
函数:-
将
g_env
数组初始化为 0。 -
从系统环境变量
environ
复制环境变量到g_env
中。 -
添加一个测试用的环境变量
"HAHA=for_test"
。 -
使用
putenv
函数将g_env
中的环境变量设置到当前进程。 -
将
environ
指针指向g_env
。
-
步骤 6:编写处理内置命令的函数
编写几个函数用于处理内置命令,如 cd
、echo
、export
和 alias
。
// 处理 cd 命令
bool Cd() {if (g_argc == 1) {const char *home = GetHome();if (home[0] != '\0') {if (chdir(home) == 0) {setenv("OLDPWD", getenv("PWD"), 1);GetPwd();}}} else {std::string target = g_argv[1];if (target == "-") {const char *old_pwd = getenv("OLDPWD");if (old_pwd != nullptr) {if (chdir(old_pwd) == 0) {setenv("OLDPWD", getenv("PWD"), 1);GetPwd();}}} else if (target == "~") {const char *home = GetHome();if (home[0] != '\0') {if (chdir(home) == 0) {setenv("OLDPWD", getenv("PWD"), 1);GetPwd();}}} else {if (chdir(target.c_str()) == 0) {setenv("OLDPWD", getenv("PWD"), 1);GetPwd();}}}return true;
}// 处理 echo 命令
void Echo() {if (g_argc == 2) {std::string arg = g_argv[1];if (arg == "$?") {std::cout << lastcode << std::endl;lastcode = 0;} else if (arg[0] == '$') {std::string env_name = arg.substr(1);const char *env_value = getenv(env_name.c_str());if (env_value != nullptr) {std::cout << env_value << std::endl;} else {std::cout << "Environment variable not found." << std::endl;}} else {std::cout << arg << std::endl;}}
}// 检查并执行内置命令
bool CheckAndExecBuiltin() {std::string cmd = g_argv[0];if (cmd == "cd") {return Cd();} else if (cmd == "echo") {Echo();return true;} else if (cmd == "export") {if (g_argc == 2) {char *equal_sign = strchr(g_argv[1], '=');if (equal_sign != nullptr) {*equal_sign = '\0';setenv(g_argv[1], equal_sign + 1, 1);}}return true;} else if (cmd == "alias") {if (g_argc == 3) {alias_list[g_argv[1]] = g_argv[2];}return true;}return false;
}
-
Cd
函数:-
如果没有参数,则切换到用户主目录。
-
如果参数是
-
,则切换到上一个工作目录。 -
如果参数是
~
,则切换到用户主目录。 -
其他情况,切换到指定目录。
-
每次切换目录后,更新
OLDPWD
环境变量并重新获取当前工作目录。
-
-
Echo
函数:-
如果参数是
$?
,则输出上一次命令的退出状态码并将其重置为 0。 -
如果参数以
$
开头,则输出对应的环境变量值,如果变量不存在则给出提示。 -
其他情况,直接输出参数内容。
-
-
CheckAndExecBuiltin
函数:-
检查命令是否为内置命令(
cd
、echo
、export
、alias
)。 -
如果是
export
命令,则设置新的环境变量。 -
如果是
alias
命令,则将别名和实际命令存储到alias_list
中。
-
步骤 7:编写辅助函数
编写一些辅助函数,用于获取目录名、生成命令行提示符、获取用户输入、解析命令行参数和打印命令行参数。
// 获取目录名
std::string DirName(const char *pwd) {std::string path = pwd;if (path == "/") return "/";size_t pos = path.rfind('/');if (pos == std::string::npos) return "BUG?";return path.substr(pos + 1);
}// 生成命令行提示符
void MakeCommandLine(char cmd_prompt[], int size) {snprintf(cmd_prompt, size, FORMAT, GetUserName(), GetHostName(), DirName(GetPwd()).c_str());
}// 打印命令行提示符
void PrintCommandPrompt() {char prompt[COMMAND_SIZE];MakeCommandLine(prompt, sizeof(prompt));std::cout << prompt;std::cout.flush();
}// 获取用户输入的命令行
bool GetCommandLine(char *out, int size) {char *input = fgets(out, size, stdin);if (input == nullptr) return false;size_t len = strlen(out);if (len > 0 && out[len - 1] == '\n') {out[len - 1] = '\0';}return len > 0;
}// 解析命令行参数
bool CommandParse(char *commandline) {g_argc = 0;g_argv[g_argc++] = strtok(commandline, " ");while ((g_argv[g_argc++] = strtok(nullptr, " ")) != nullptr);--g_argc;return g_argc > 0;
}// 打印命令行参数
void PrintArgv() {for (int i = 0; g_argv[i]; ++i) {std::cout << "argv[" << i << "]->" << g_argv[i] << std::endl;}std::cout << "argc: " << g_argc << std::endl;
}
-
DirName
函数:从路径中提取目录名。 -
MakeCommandLine
函数:按照FORMAT
格式生成命令行提示符。 -
PrintCommandPrompt
函数:打印生成的命令行提示符并刷新输出缓冲区。 -
GetCommandLine
函数:从标准输入读取用户输入的命令行,去除换行符。 -
CommandParse
函数:使用strtok
函数将命令行分割成参数,存储到g_argv
中。 -
PrintArgv
函数:打印命令行参数和参数数量。
步骤 8:编写执行外部命令的函数
编写一个函数用于执行外部命令,使用 fork
创建子进程,在子进程中使用 execvp
执行命令。
// 执行外部命令
int Execute() {pid_t pid = fork();if (pid == 0) {if (execvp(g_argv[0], g_argv) == -1) {perror("execvp");exit(EXIT_FAILURE);}} else if (pid > 0) {int status;waitpid(pid, &status, 0);lastcode = WEXITSTATUS(status);} else {perror("fork");}return 0;
}
-
Execute
函数:-
使用
fork
函数创建子进程。 -
子进程使用
execvp
函数执行外部命令,如果执行失败则输出错误信息并退出。 -
父进程使用
waitpid
函数等待子进程结束,获取退出状态码并保存到lastcode
中。
-
步骤 9:编写主函数
最后,编写主函数,初始化环境变量,进入无限循环,不断获取用户输入的命令并执行。
// 主函数
int main() {InitEnv();while (true) {PrintCommandPrompt();char commandline[COMMAND_SIZE];if (!GetCommandLine(commandline, sizeof(commandline))) {continue;}if (!CommandParse(commandline)) {continue;}if (CheckAndExecBuiltin()) {continue;}Execute();}// 释放环境变量内存for (int i = 0; i < g_envs; ++i) {free(g_env[i]);}return 0;
}
main
函数:
-
调用
InitEnv
函数初始化环境变量。 -
进入无限循环,不断打印命令行提示符。
-
获取用户输入的命令行并进行解析。
-
检查是否为内置命令,如果是则执行并继续循环。
-
如果不是内置命令,则调用
Execute
函数执行外部命令。 -
程序结束前,释放
g_env
数组中分配的内存。
步骤 10:编译和运行程序
终端中,使用 g++
编译器编译 my_shell.cpp
文件:
g++ my_shell.cpp -o my_shell
编译成功后,会生成一个名为 my_shell
的可执行文件。运行该文件:
./my_shell
全代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstring>
#include <unordered_map>#define COMMAND_SIZE 1024
#define FORMAT "[%s@%s %s]# "// 下面是shell定义的全局数据// 1. 命令行参数表
#define MAXARGC 128
char *g_argv[MAXARGC];
int g_argc = 0; // 2. 环境变量表
#define MAX_ENVS 100
char *g_env[MAX_ENVS];
int g_envs = 0;// 3. 别名映射表
std::unordered_map<std::string, std::string> alias_list;// for test
char cwd[1024];
char cwdenv[2048]; // 增大缓冲区,避免snprintf警告// last exit code
int lastcode = 0;const char *GetUserName()
{const char *name = getenv("USER");return name == NULL? "None" : name;
}const char *GetHostName()
{const char *hostname = getenv("HOSTNAME");return hostname == NULL? "None" : hostname;
}const char *GetPwd()
{const char *pwd = getcwd(cwd, sizeof(cwd));if(pwd != NULL){snprintf(cwdenv, sizeof(cwdenv), "PWD=%s", cwd);putenv(cwdenv);}return pwd == NULL? "None" : pwd;
}const char *GetHome()
{const char *home = getenv("HOME");return home == NULL? "" : home;
}void InitEnv()
{extern char **environ;memset(g_env, 0, sizeof(g_env));g_envs = 0;// 本来要从配置文件来// 1. 获取环境变量for(int i = 0; environ[i]; i++){// 1.1 申请空间g_env[i] = (char*)malloc(strlen(environ[i]) + 1);strcpy(g_env[i], environ[i]);g_envs++;}g_env[g_envs++] = (char*)"HAHA=for_test"; // for_testg_env[g_envs] = NULL;// 2. 导成环境变量for(int i = 0; g_env[i]; i++){putenv(g_env[i]);}environ = g_env;
}// command
bool Cd()
{// cd argc = 1if(g_argc == 1){std::string home = GetHome();if(home.empty()) return true;chdir(home.c_str());}else{std::string where = g_argv[1];// cd - / cd ~if(where == "-"){const char *old_pwd = getenv("OLDPWD");if (old_pwd){chdir(old_pwd);setenv("OLDPWD", getcwd(cwd, sizeof(cwd)), 1);}}else if(where == "~"){std::string home = GetHome();if (!home.empty()){chdir(home.c_str());}}else{chdir(where.c_str());}}return true;
}void Echo()
{if(g_argc == 2){// echo "hello world"// echo $?// echo $PATHstd::string opt = g_argv[1];if(opt == "$?"){std::cout << lastcode << std::endl;lastcode = 0;}else if(opt[0] == '$'){std::string env_name = opt.substr(1);const char *env_value = getenv(env_name.c_str());if(env_value)std::cout << env_value << std::endl;else{std::cout << "Environment variable not found." << std::endl;}}else{std::cout << opt << std::endl;}}
}// / /a/b/c
std::string DirName(const char *pwd)
{
#define SLASH "/"std::string dir = pwd;if(dir == SLASH) return SLASH;auto pos = dir.rfind(SLASH);if(pos == std::string::npos) return "BUG?";return dir.substr(pos + 1);
}void MakeCommandLine(char cmd_prompt[], int size)
{snprintf(cmd_prompt, size, FORMAT, GetUserName(), GetHostName(), DirName(GetPwd()).c_str());//snprintf(cmd_prompt, size, FORMAT, GetUserName(), GetHostName(), GetPwd());
}void PrintCommandPrompt()
{char prompt[COMMAND_SIZE];MakeCommandLine(prompt, sizeof(prompt));printf("%s", prompt);fflush(stdout);
}bool GetCommandLine(char *out, int size)
{// ls -a -l => "ls -a -l\n" 字符串char *c = fgets(out, size, stdin);if(c == NULL) return false;out[strlen(out) - 1] = 0; // 清理\nif(strlen(out) == 0) return false;return true;
}// 3. 命令行分析 "ls -a -l" -> "ls" "-a" "-l"
bool CommandParse(char *commandline)
{
#define SEP " "g_argc = 0;// 命令行分析 "ls -a -l" -> "ls" "-a" "-l"g_argv[g_argc++] = strtok(commandline, SEP);while((bool)(g_argv[g_argc++] = strtok(nullptr, SEP)));g_argc--;return g_argc > 0? true:false;
}void PrintArgv()
{for(int i = 0; g_argv[i]; i++){printf("argv[%d]->%s\n", i, g_argv[i]);}printf("argc: %d\n", g_argc);
}bool CheckAndExecBuiltin()
{std::string cmd = g_argv[0];if(cmd == "cd"){Cd();return true;}else if(cmd == "echo"){Echo();return true;}else if(cmd == "export"){if (g_argc == 2){std::string var = g_argv[1];char *equal_pos = strchr(var.c_str(), '=');if (equal_pos){*equal_pos = '\0';setenv(var.c_str(), equal_pos + 1, 1);}}return true;}else if(cmd == "alias"){if (g_argc == 3){std::string nickname = g_argv[1];std::string real_cmd = g_argv[2];alias_list[nickname] = real_cmd;}return true;}return false;
}int Execute()
{pid_t id = fork();if(id == 0){// childexecvp(g_argv[0], g_argv);exit(1);}int status = 0;// fatherpid_t rid = waitpid(id, &status, 0);if(rid > 0){lastcode = WEXITSTATUS(status);}return 0;
}int main()
{// shell 启动的时候,从系统中获取环境变量// 我们的环境变量信息应该从父shell统一来InitEnv();while(true){// 1. 输出命令行提示符PrintCommandPrompt();// 2. 获取用户输入的命令char commandline[COMMAND_SIZE];if(!GetCommandLine(commandline, sizeof(commandline)))continue;// 3. 命令行分析 "ls -a -l" -> "ls" "-a" "-l"if(!CommandParse(commandline))continue;//PrintArgv();// 检测别名// 4. 检测并处理内键命令if(CheckAndExecBuiltin())continue;// 5. 执行命令Execute();}// 释放内存for (int i = 0; i < g_envs; ++i){free(g_env[i]);}return 0;
}
相关文章:
分布自定义shell脚本(详写)附带全代码
涉及知识全排列 常见指令 小知识点 操作系统 什么是进程 进程控制 步骤 1:项目准备 在开始编写代码之前,你需要创建一个新的项目文件夹,并在其中创建一个 .cpp 文件,例如 my_shell.cpp。同时,确保你已经安装了 C…...
windows拷贝文件脚本
1、新建脚本文件xxx.bat,名字任意,后缀未.bat即可,将以下内容拷贝进去,修改src和des为自己文件的目录即可。 echo off :: 设置字符集为UTF-8,命令窗口能正确显示中文字符。 chcp 65001 rem 读取当前目录并进入当前目…...
Arduino编译和烧录STM32——基于J-link SWD模式
一、安装Stm32 Arduino支持 在arduino中添加stm32的开发板地址:https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json 安装stm32开发板支持 二、安装STM32CubeProgrammer 从stm32网站中安装:https://ww…...
Java表达式2.0
1 .数据类型转换 自动类型转换的规则 自动类型转换遵循一定的规则,这些规则确保了转换的合理性和安全性。以下是自动类型转换的主要规则: 容量小的类型自动转换为容量大的类型 Java中,数据类型的容量从小到大依次为:byte → shor…...
【概率论,算法】排列的峰值期望
Surtr1 的珂学难题 题目链接:https://ac.nowcoder.com/acm/contest/107965/E 给定一个长度为 n n n 的排列 p p p,排列中任一位置如果满足以下条件,则称该位置为 峰值: 位置 1:若存在元素,满足 p [ 1 ] > p […...
清理C盘组合拳:最高释放空间80GB+
分享一套系统化的C盘清理方案,涵盖从基础清理到深度优化的8个关键步骤,结合安全性与效率,可快速释放5-50GB空间: 一、精准定位空间占用源(必备工具) 空间可视化分析 使用 TreeSize Free 或 WizTree 扫描C…...
容器中的对象切片问题
C 容器(如 std::vector、std::list 等) 通常存储对象的副本,而非指向对象的指针。因此,当与继承结合使用时,可能导致 切片(Object Slicing) 问题,即仅存储基类部分,丢失派…...
SpringBoot编写单元测试
pom.xml引入单元测试的坐标 <!--单元测试坐标--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>编写单元测试类 测试类…...
二、在springboot 中使用 AIService
在上一篇文章中,我们介绍了如何使用langchain4j实现简单的问答功能,本篇文章我们将介绍如何在springboot中使用AIService。 1.实现原理 先看下AiService注解所在的依赖langchain4j-spring-boot-starter中包含什么内容: 1.1 event.AiServi…...
拼多多面经,暑期实习Java一面
项目中的设计模式 mysql连接过程,索引,分库分表场景,路由策略 redis使用场景,分片集群怎么搭建与路由,数据一致性 分布式锁怎么用的,具体使用参数 线程池怎么用的,过程 sql having 分布式事务 如…...
Function calling LLMs 的 MCP:AI开发的双剑合璧
🧠 向所有学习者致敬! “学习不是装满一桶水,而是点燃一把火。” —— 叶芝 我的博客主页: https://lizheng.blog.csdn.net 🌐 欢迎点击加入AI人工智能社区! 🚀 让我们一起努力,共创AI未来! 🚀 在 MCPs 成为主流(或者像现在这样火得一塌糊涂)之前,大多数 AI …...
数字系统与编码
1. 数字系统(Number Systems) 1.1 常见数字系统 系统基数符号集示例应用场景二进制20, 11010计算机底层电路、数据存储八进制80-717Unix文件权限(如chmod 755)十进制100-942日常计算十六进制160-9, A-F0x1F内存地址、颜色编码&a…...
Pytorch实战
1、安装 安装 conda, Python工具大全,方便管理多个 Python 环境,必须选择跟自己环境配套的版本。 https://www.anaconda.com 网速慢的,可以参考国内源,也可以去这里看看: torch PyPI Index of /anaconda/miniconda…...
如何高效利用呼叫中心系统和AI语音机器人
要更好地使用呼叫中心系统和语音机器人,需要结合两者的优势,实现自动化、智能化、高效率的客户服务与业务运营。以下是优化策略和具体实践方法: 一、呼叫中心系统优化 1. 智能路由与IVR优化 智能ACD(自动呼叫分配) …...
LeetCode[232]用栈实现队列
思路: 一道很简单的题,就是栈是先进后出,队列是先进先出,用两个栈底相互对着,这样一个队列就产生了,右栈为空的情况,左栈栈底就是队首元素,所以我们需要将左栈全部压入右栈ÿ…...
using用法整理
using 的极简新手教程,用最直白的语言和代码解释: 美图美图 一、核心作用:给类型起别名 目的:让复杂类型名变短、变好记。 例子: // 原名:std::vector<std::string> // 起个别名就叫 StringList…...
《猎豹夕阳》
年少时很喜欢的一篇文章,曾和挚友一遍又一遍的记诵,今天又偶然遇到他,转载如下: 我第一次见到它,是在风雪的夜里。我不会抱怨这种天气,因为我是个优秀的登山探险者,我必须在这种天气下工作。我…...
【AI训练环境搭建】在Windows11上搭建WSL2+Ubuntu22.04+Tensorflow+GPU机器学习训练环境
一、安装Ubuntu 拿到该文件Ubuntu-22.04.tar 通过wsl导入该虚拟机镜像,然后查看wsl虚拟机列表。 wsl --import Ubuntu-22.04-tensorflow D:\wsl-data\Ubuntu-22.04-tensorflow D:\wsl-data\temp\Ubuntu-22.04.tarwsl -l 进入虚拟机 wsl -d Ubuntu-22.04-tensorfl…...
如何轻松实现用户充值系统的API自动化测试
在现代软件开发中,API(应用程序编程接口)作为连接不同系统和模块的关键组件,其重要性日益凸显。随着软件应用的互联性不断增强,API的数量和复杂度也在不断增加。传统的API测试方法面临着诸多挑战: 1.手动测…...
Python 一等函数( 高阶函数)
高阶函数 接受函数为参数,或者把函数作为结果返回的函数是高阶函数(higherorder function)。map 函数就是一例,如示例 5-2 所示。此外,内置函 数 sorted 也是:可选的 key 参数用于提供一个函数,…...
用于手部康复设备的TinyML语音分类嵌入式人工智能模块
论文标题 英文标题:TinyML Speech Classification Embedded AI Module for Hand Rehabilitation Device 中文标题:用于手部康复设备的 TinyML 语音分类嵌入式人工智能模块 作者信息 Arkorn Numsomran:Triam Udom Suksa Pattanakarn Suvarna…...
【HarmonyOS 5】VisionKit人脸活体检测详解
【HarmonyOS 5】VisionKit人脸活体检测详解 一、VisionKit人脸活体检测是什么? VisionKit是HamronyOS提供的场景化视觉服务工具包。 华为将常见的解决方案,通常需要三方应用使用SDK进行集成。华为以Kit的形式集成在HarmoyOS系统中,方便三方…...
Linux操作系统--进程的创建和终止
目录 1.进程创建 1.1fork()函数初识 1.2写时拷贝 1. 提升系统效率 2. 隔离错误影响 3. 支持并行计算 2.进程终止: 2.1进程退出场景: 2.2进程常见退出方法: 2.3_exit()系统调用接口 2.4exit函数 2.5return退出 1.进程创建 1.1for…...
算法分析传输加密数据格式密文存储代码混淆逆向保护
代码混淆 一.基本概念java的bytecode很容易通过JAD等反编译工具还原出源代码。这样势必不满足安全的定义。如何一定程度上保护需要防止被反编译的源代码呢?混淆(obfuscate)技术注意:用obfuscate防盗版是根本不可能,连汇…...
从事计算机视觉需要掌握哪些知识
目录 基础数学知识 计算机科学基础 传统计算机视觉知识 机器学习与深度学习知识 其他知识 计算机视觉是一门让计算机从图像或视频中获取有意义信息的跨学科领域,从事该领域需要掌握多方面的知识,以下详细介绍: 基础数学知识 线性代数 &…...
Android Studio 中 Drawable 详细全解
文章目录 一、Drawable 概述二、Drawable 类型详解1. 位图 Drawable (BitmapDrawable)2. 矢量 Drawable (VectorDrawable)3. 形状 Drawable (ShapeDrawable)4. 图层 Drawable (LayerDrawable)5. 状态列表 Drawable (StateListDrawable)6. 级别列表 Drawable (LevelListDrawable…...
【实战中提升自己】内网安全部署之端口隔离与MAC地址认证
1 1拓扑 「模拟器、工具合集」复制整段内容 链接:https://docs.qq.com/sheet/DV0xxTmFDRFVoY1dQ?tab7ulgil 1 端口隔离技术部署 [boss]port-group 1 [boss-port-group-1]port-isolate enable 说明:这里有几个地方不需要部署…...
Linux 420 find stat touch tree scp crontab
准备安装CentOSstream https://blog.csdn.net/s_alted/article/details/117739735 官网 CentOS 9 “Couldn’t open file /mnt/repodata/repomd.xml” deepseek 下载成功 树状 另一台虚拟机...
基于 Vue3 + ECharts + GeoJson 实现区域地图钻取功能详解
文章目录 前言一、实现步骤1. 项目初始化2. 准备GeoJson数据3. 创建地图组件4. 创建主页面组件5. 使用组件 二、功能亮点三、性能优化建议四、常见问题解决五、结语六、实战demo七、资源下载 前言 在数据可视化领域,地图展示是一种非常直观的表现形式。而地图钻取&…...
算法题(129):二维前缀和
审题: 本题需要我们将q组矩阵的和打印出来 思路: 方法一:二维前缀和 由于本题使用暴力的模拟方法运行次数高达1e11,会超时,所以我们采用运行次数在1e6的二维前缀和来解题 第一步:前缀和的求法 x i…...
NEAT 算法解决 Lunar Lander 问题:从理论到实践
NEAT 算法解决 Lunar Lander 问题:从理论到实践 0. 前言1. 定义环境2. 配置 NEAT3. 解决 Lunar lander 问题小结系列链接0. 前言 在使用 NEAT 解决强化学习问题一节所用的方法只适用于较简单的强化学习 (reinforcement learning, RL) 环境。在更复杂的环境中使用同样的进化解…...
Arduino示例代码讲解:Project 07 - Keyboard 键盘
Arduino示例代码讲解:Project 07 - Keyboard 键盘 Project 07 - Keyboard 键盘程序功能概述功能:硬件要求:输出:代码结构全局变量`setup()` 函数`loop()` 函数读取电位器值:打印电位器值:播放音调:运行过程注意事项Project 07 - Keyboard 键盘 /*Arduino Starter Kit e…...
4.凸包-Graham Scan
Graham Scan:Algorithm Preprocessing 根据角度进行排序 Graham Scan 例子 例2 Graham Scan:Correctness Left Turn/right Trun 下一个点出现的两种情况:非蓝即绿 Presorting 预排序很重要:否则所有的点都会满足 to-left-test BackTracks算法复杂度 …...
系统架构师2025年论文《论SOA技术的应用》
摘要: 本人于XXXX年XX月参加某市医院《预约挂号系统》的开发工作,在该项目中主要担任系统架构师,主要负责该系统架构和网络安全体系架构设计。经过多年的医院信息化建设,某市医院已经建立了一些应用系统,但是…...
React+TS编写轮播图
当前轮播图存在部分问题,一次循环结束,进入下一次需要点击两次(所以动画效果上点击第二次才出现) 轮播图:实现无限循环轮播图的关键在于"视觉欺骗"——我们在实际数据的前后各添加部分数据副本,当…...
山东大学创新项目实训开发日志(19)之前端知识深度学习
今天晚上在队长的带领下学习了一下前端vue的基础知识 reactive和ref函数 refreactive数据类型原始数据、对象对象操作js中需要添加.value,tamplate中则不用都不用添加.value computed和watch computed 写法 <script setup>const Factorial computed(() &g…...
【C++详解】C++入门(一)
文章目录 一、命名空间命名空间的基本特性命名空间的使用 二、C输入输出用法三、缺省参数(默认参数)定义用法 四、函数重载 一、命名空间 命名空间的基本特性 #include <stdio.h> #include <stdlib.h>int rand 10;int main() {// 编译报错:error C23…...
MAC-从es中抽取数据存入表中怎么实现
使用 Java 从 Elasticsearch 抽取数据并存入数据库表的完整实现方案: 1. Maven 依赖配置 <dependencies><!-- Elasticsearch --><dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-c…...
Android串口通信
最近因为需要在Android平台进行电子秤的开发,首先第一步就是需要解决Android串口通信获取电子秤的称重信息。 google官方给我们提供了现成的解决方案,里面有编译好的apk文件还有源代码可以直接参考使用。地址:http://code.google.com/p/andr…...
QT常见输入类控件及其属性
Line Edit QLineEdit用来表示单行输入框,可以输入一段文本,但是不能换行 核心属性: 核心信号 信号 说明 void cursorPositionChanged(int old,int new) 当鼠标移动时发出此型号,old为先前位置,new为新位置 void …...
RAG 与 MCP 如何以不同方式解决大模型的局限性
Claude 和 GPT-4o 等大型语言模型 (LLM) 功能强大,但也面临两个主要限制:它们包含的知识是时效性的(更具体地说,是在训练时点固定的),并且决定它们一次可以处理多少信息的上下文窗口是有限的。 检索增强生…...
[Windows]_[VS2017]_[如何进行远程调试程序]
场景 在开发Windows程序时,有时候在测试机上测试出异常操作的情况,在开发机上就是出现不了。还比如在测试机上能测试到崩溃的情况,在开发机上也是重现不了,怎么办? 说明 这种情况可能是测试机上的系统版本࿰…...
Retinex系列图像/视频增强算法介绍
Retinex 系列原理基础 一、核心原理与理论 Retinex算法基于人类视觉系统特性,认为观测到的图像由光照分量(L)与反射分量( R )乘积构成,即: S ( x , y ) = L ( x , y...
游戏引擎学习第237天:使用 OpenGL 显示图像
win32_game.cpp: 禁用 PFD_DOUBLEBUFFER 我们正在处理一个新的开发阶段,目标是在使用 OpenGL 渲染的同时能正常通过 OBS 进行直播。昨天我们已经尝试了一整天来解决这个问题,希望能找到一种方式让 OBS 能正确地捕捉到 OpenGL 的窗口画面。虽然我们不确定…...
【C++基本算法】背包问题——完全背包
7. 背包问题——完全背包 文章目录 7. 背包问题——完全背包【模板】完全背包零钱兑换零钱兑换∥完全平方数问题解决注意事项 【模板】完全背包 题目链接: 【模板】完全背包 要点: 完全背包核心逻辑:物品无限次选择,状态转移方…...
Spring 01
今天是2025/0420 19:44 day 21 总路线请移步主页Java大纲相关文章 今天进行Spring 1,2,3 个模块的归纳 最近在忙毕设,更新有点慢,见谅 首先是Spring 的相关内容概括的思维导图 一、核心概念详解 1. IoC容器 1.1 工作原理 // 典型使用示例 Applica…...
小迪第10天http/s数据包
HTTP数据包 浏览器请求&请求头&响应头 浏览器访问流程 请求:用户–>web服务器 (Request) 响应:web服务器–> 用户(Response) 加代理后 请求:用户–>代理–>web服务器 (Request) 响应:web服务器–>代理–> 用户(Response) http GET请求头 http post…...
网络设备基础运维全攻略:华为/思科核心操作与巡检指南
一、设备登录与基础操作体系 1. 安全登录策略与环境准备 (1)登录方式深度解析 协议华为/H3C命令思科命令安全性应用场景Telnettelnet 192.168.1.1telnet 192.168.1.1明文传输本地测试(禁止公网使用)SSHssh -l admin 192.168.1.…...
Jsp技术入门指南【八】利用EL表达式开发无脚本的JSP页面
Jsp技术入门指南【八】利用EL表达式开发无脚本的JSP页面 前言一、什么是EL?二、EL如何访问作用域?2.1 对比传统脚本 vs EL2.2 EL的“自动搜索机制” 三、EL运算规则:什么能相加?什么不能?四、EL如何访问集合和数组&…...
MySQL数据库(基础篇)
一:MySQL的概述 1:MySQL数据库的下载地址 MySQL :: 下载 MySQL 安装程序 2:MySQL的客户端连接方式 1:使用Mysql自带的来连接 2:使用windows自带的命令行来来连接(需要配置path环…...