前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【Linux篇】自主Shell命令行解释器

【Linux篇】自主Shell命令行解释器

作者头像
_孙同学
发布于 2025-04-03 00:37:40
发布于 2025-04-03 00:37:40
10400
代码可运行
举报
文章被收录于专栏:技术分享技术分享
运行总次数:0
代码可运行

1. 获取用户名的接口

通过环境变量来获取 我们需要用到的接口getenv

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//获取用户名
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 = getenv("PWD");
	return pwd == NULL ? "None" : pwd;
}

2. 等待用户输入接口

当我们没有输入时,我们会发现命令行会卡在这里等待我们输入

我们也让我们自己的命令行能等待输入

我们可以采用fgets以文件形式读取一行,也可以使用gets读取一行字符串 我们接下来进行C/C++混编的方式,因为我们后面会用到系统调用,而这些系统调用都是用C写的,如果我们纯用C++来实现的话可能会要适配某些接口。 我们下来用fgets实现

效果展示:

我们会发现最后多了一个空行,这里为什么会多一个空行呢?因为我们在输入完字符串后还按了一次回车,我们不想让它有这一行空行该怎么办?我们在输入字符串后后面还会有个\n,比如我们输入的是"ls -a -l"最后再按一次回车就变成了"ls -a -l \n",我们只需要输入完之后把最后的\n置为0就好了

效果展示:

🔖小tips: 这里会不会求出的字符串长度为0,然后再-1发生越界呢?答案是不会的,因为我们最后至少还要敲一次回车键,所以这个字符串的最小长度为1

3. 将上述代码进行面向对象式的封装

我们先认识一个新的接口snprintf

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//制作命令行提示符
void MakeCommandline(char com_prompt[], int size)
{
	snprintf(com_prompt, size, FORMAT, GetUserName(), GetHostName(), GetPwd());//我们想让"[%s@%s %s]# "以后能随便调整,所以我们define一下
}

//打印命令行提示符
void PrintCommandline()
{
	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"
	const char* c = fgets(out, size, stdin);//从标准输入里获取,放到out当中
	if (c == NULL) return 1;
	out[strlen(out) - 1] = 0;//清理\n 
	if (strlen(out) == 0) return false; //对于我们用户来说,有可能获取到的字符串的长度为0,为0直接return false 
	return true; //否则return true
}

int main()
{
	//printf("[%s@%s %s]# ",GetUserName(),GetHostName(),GetPwd());
    //1. 打印命令行提示符
	PrintCommandline();

	//2.获取用户输入
	char commandline[COMMAND_SIZE];//定义一个数组
	if (GetCommandline(commandline, sizeof(commandline)))//如果获取成功
	{
		printf("echo %s\n", commandline);//回显一下我们输入的内容,用作测试
	}

	return 0;
}

我们在shell中可以一直输入,我们的程序输入一次就结束了,所以shell永远不退出。我们应当不断地获取用户输入。

4. 命令行解析

我们在传字符串的时候不能“ls -a -l”整体传入,我们要将传入的字符串进行变形,将这一个字符串拆成“ls” "-a" "-l"。而且我们的命令行也不能在shell中直接替换,而要创建子进程。我们将字符串切成这样那么如何快速的找到每一个元素呢?命令行参数表 将打散的字符串以NULL结尾放到g_argv[]里面。在这里又来认识一个新的接口strtok

这个接口第一次切的时候第一个参数传的是要分割的字符串的起始地址,如果要接着切的话第一个参数就必须传NULL,当切除完毕返回值就为空表示没有字符串了。 分隔符是const char*所以我们不能传单引号,而要传双引号

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//命令行分析
bool CommandParse(char* commandline)
{
#define SEP " "
	g_argc = 0; //每次进来初始化为0
	//"ls -a -l" => "ls" "-a" "-l"
	g_argv[g_argc++] = strtok(commandline, SEP);

	while (g_argv[g_argc++] = strtok(nullptr, SEP));//再次想切的话传commandline就不对了,再要切历史字符串就得把它设为nullptr,再次切的话分隔符依旧是SEP,如果切成了返回的就是下一个字符串的起始地址
	//为什么可以这样切呢?因为再次切字串时,它一直切一直切最后就会会变成NULL,切成NULL首先会把g_argv数组置为NULL,符合命令行参数表的设定,NULL也会作为while的条件判断,最后就直接结束了
		 //并且g_argc也会统计出命令行参数有多少个
	g_argc--;//因为NULL也被统计到了里面
	return true;
}

 //测试形成的表结构
void PrintArgv()
{
	for (int i = 0; i < g_argc; i++)
	{
		printf("argv[%d]->%s\n", i, g_argv[i]);
	}
	printf("argc:%d", g_argc);
}

5. 执行命令

由于我们当前的进程还有自己的任务,所以我们将执行命令交给子进程来完成,那么就需要程序替换,execvp

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//执行命令
int Execute()
{
	pid_t id = fork();
	if (id == 0)
	{
		//子进程
		execvp(g_argv[0], g_argv);
		exit(1);
	}
	//父进程
	pid_t rid = waitpid(id, nullptr, 0);
	return 0;
}

6. 路径切割

系统的路径名只有一个,我们自己写的会跟一长串

所以我们对路径进行切割。 C++中有个命令rfind从后向前找,substr截字符串

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//路径切割
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);
}

7. 解决cd命令路径不变

到目前我们会发现我们执行cd命令时路径不发生改变,因为目前所有的命令都是子进程执行的,子进程改变路径时改的是自己的pwd,父进程bash的环境变量并没有改变,我们真正要改的是父进程的路径,因为把父进程的路径改了往后再创建子进程所有的子进程就会在新的路径下执行,因为所有的子进程的PCB都是拷贝父进程的PCB,因此cd这样的命令不能让子进程去执行,而要让父进程亲自执行,这种命令叫做内建命令 如何让bash亲自去执行呢?我们先来认识一个新的接口chdir

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 //处理cd命令
bool cd()
{
	if (g_argc == 1) //表明只是cd,没有带任何参数
	{
		std::string home = GetHome();//将home的路径拿过来
		if (home.empty())  return true;//如果是空就相当于环境变量获取失败了
		chdir(home.c_str());//走到这里不为空,就把当前路径切换成家路径了
	}
	else
	{
		std::string where = g_argv[1];
		//"cd -" / "cd ~"
		if (where == "-")
		{

		}
		else if (where == "~")
		{

		}
		else
		{
			chdir(where.c_str());
		}
	}
}
 //检测并处理内建命令
bool CheckAndExecBuiltin()
{
	std::string cmd = g_argv[0];
	if (cmd == "cd")//如果是内建命令
	{
		cd();
		return true;//是内建命令
	}
	return false;//否则不是内建命令
}

8. 解决cd后环境变量未发生变化

我们再切换路径后会发现路径变了,但是环境变量中的路径并没有变。原因是路径发生变化后环境变量没有进行刷新,所以我们要将新的路径更新到环境变量中。这里我们来认识一个系统调用getcwd,获取当前进程的工作路径。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 //获取当前路径
const char* GetPwd()
{
	//const char* pwd = getenv("PWD");
	const char* pwd = getcwd(cwd, sizeof(cwd));
	if (pwd != NULL)
	{
		snprintf(cwdenv, sizeof(cwdenv), "PWD=%s", cwd);//获得环境变量
		putenv(cwdenv);//将环境变量导给当前进程
	}
	return pwd == NULL ? "None" : pwd;
}

9. echo命令

echo命令也是内建命令,我们可以用它echo "hello"在屏幕上打印,echo

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//处理echo命令
void Echo()
{
	if (g_argc == 2)//意思是echo后面必须得跟东西
	{
		//echo "heool world"
		   //echo $?
			//echo $PATH
		std::string opt = g_argv[1];
		if (opt == "$?")//输出上一个程序退出的退出码
		{
			std::cout << lastcode << std::endl;
			lastcode = 0;//lastcode清零
		}
		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 << opt << std::endl;
		}
	}
}

10. 获取环境变量

shell启动时需要从系统中获取环境变量,但是我们还做不到从配置文件中读,今天我们直接从父shell中拿就可以了,我们自己维护一张环境变量表,然后将表导进环境变量空间就行。 我们又用到一个接口environ

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 //初始化环境变量表
void InitEnv()
{
	extern char** environ;//声明一个环境变量所对应的信息
	memset(g_env, 0, sizeof(g_env));//将表中的信息全部置为0
	g_envs = 0;

	//本来要从配合文件中来
	//今天从父shell中来
	//1. 获取环境变量
	for (int i = 0; environ[i]; i++)
	{
		g_env[i] = (char*)malloc(strlen(environ[i]) + 1);
		//1.2拷贝
		strcpy(g_env[i], environ[i]);//把父进程环境变量里的值拷贝给g_env
		g_envs++;
	}
	g_env[g_envs] = NULL;
	//2.导入环境变量
	for (int i = 0; g_env[i]; i++)
	{
		putenv(g_env[i]);
	}
	environ = g_env;
	//3.clean清理
}

11. 总结

用下图的时间轴来表示事件的发生次序。其中时间从左向右。shell由标识为sh的方块代表,它随着时间的流逝从左向右移动。shell从用户读入字符串"ls"shell建立一个新的进程,然后在那个进程中运行ls程序并等待那个进程结束。

然后shell读取新的一行输入,建立一个新的进程,在这个进程中运行程序并等待这个进程结束。所以要写一个shell,需要循环以下过程:

  • 获取命令行
  • 解析命令行
  • 建立⼀个子进程(fork)
  • 替换子进程(execvp)
  • 父进程等待子进程退出(wait)

12.代码实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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]# "
#define MAXARGC 128

//命令行参数表
char* g_argv[MAXARGC];//全局的命令行参数表
int g_argc = 0;

//环境变量表
#define MAX_ENVS 100
char* g_env[MAX_ENVS];//正常情况下shell启动时应该从配置文件中读取环境变量来填充这张环境变量表,也就是说当shell启动时就应该拿环境变量表来初始化它
int g_envs = 0;//环境变量的个数

//别名映射表
std::unordered_map<std::string,std::string> alias_list;


//定义一个cwd
char cwd[1024];
char cwdenv[1024];//当前工作路径的env

//最新程序的退出码 last exit cide
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 = getenv("PWD");
    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));//将表中的信息全部置为0
    g_envs = 0;

    //本来要从配合文件中来
    //今天从父shell中来
    //1. 获取环境变量
    for(int i = 0;environ[i];i++)
    {
        //1.1申请空间
        g_env[i] = (char*)malloc(strlen(environ[i])+1);
        //1.2拷贝
        strcpy(g_env[i],environ[i]);//把父进程环境变量里的值拷贝给g_env
        g_envs++;
    }
    g_env[g_envs] = NULL;
    //2.导入环境变量
    for(int i = 0;g_env[i];i++)
    {
        putenv(g_env[i]);
    }
    environ = g_env;
    //3.clean清理
}

//处理cd命令
bool cd()
{
    if(g_argc == 1) //表明只是cd,没有带任何参数
    {
        std::string home = GetHome();//将home的路径拿过来
        if(home.empty())  return true;//如果是空就相当于环境变量获取失败了
        chdir(home.c_str());//走到这里不为空,就把当前路径切换成家路径了
    }
    else
    {
        std::string where = g_argv[1];
        //"cd -" / "cd ~"
        if(where == "-")
        {
        
        }
        else if(where == "~")
        {
        
        }
        else
        {
            chdir(where.c_str());
        }
    }
    return true;
}

//处理echo命令
void Echo()
{
    if(g_argc == 2)//意思是echo后面必须得跟东西
    {
        //echo "heool world"
        //echo $?
        //echo $PATH
        std::string opt = g_argv[1];
        if(opt == "$?")//输出上一个程序退出的退出码
        {
            std::cout << lastcode <<std::endl;
            lastcode = 0;//lastcode清零
        }
        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 << opt << std::endl;
        }
    }   

}

//路径切割
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 com_prompt[],int size)
{
    //snprintf(com_prompt, size, FORMAT,GetUserName(),GetHostName(),GetPwd());//我们想让"[%s@%s %s]# "以后能随便调整,所以我们define一下
    snprintf(com_prompt, size, FORMAT,GetUserName(),GetHostName(),DirName(GetPwd()).c_str());//我们想让"[%s@%s %s]# "以后能随便调整,所以我们define一下
}

//打印命令行提示符
void PrintCommandline()
{
    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"
    const char *c = fgets(out,size,stdin);//从标准输入里获取,放到out当中
    if(c == NULL) return 1;
    out[strlen(out)-1] = 0;//清理\n 
    if(strlen(out) == 0) return false; //对于我们用户来说,有可能获取到的字符串的长度为0,为0直接return false 
    return true; //否则return true
}

//命令行分析
 bool CommandParse(char* commandline)
{
#define SEP " "
    g_argc = 0; //每次进来初始化为0
    //"ls -a -l" => "ls" "-a" "-l"
    g_argv[g_argc++] = strtok(commandline,SEP);
    
   while((bool)(g_argv[g_argc++] = strtok(nullptr,SEP)));//再次想切的话传commandline就不对了,再要切历史字符串就得把它设为nullptr,再次切的话分隔符依旧是SEP,如果切成了返回的就是下一个字符串的起始地址
   //为什么可以这样切呢?因为再次切字串时,它一直切一直切最后就会会变成NULL,切成NULL首先会把g_argv数组置为NULL,符合命令行参数表的设定,NULL也会作为while的条件判断,最后就直接结束了
   //并且g_argc也会统计出命令行参数有多少个
   g_argc--;//因为NULL也被统计到了里面
   return g_argc > 0 ? true : false;
}

//测试形成的表结构
void PrintArgv()
{
    for(int i = 0;i < g_argc; 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;//内建命令执行完后return true
    }
    else if(cmd == "export")
    {
        
    }
    else if(cmd == "alias")//说明是一个别名
    {
        //std::string nickname = g_argv[1];
       // alisa_list.insert(k,v);
    }
    return false;//否则不是内建命令
}

//执行命令
int Execute()
{
    pid_t id = fork();
    if(id == 0)
    {
        //子进程
        execvp(g_argv[0],g_argv);
        exit(1);
    }
    int status = 0;//退出信息
    //父进程
    pid_t rid = waitpid(id, &status, 0);
    if(rid > 0) //说明等成功了
    {
        lastcode = WEXITSTATUS(status);//最后一个进程退出的退出码
    }
    return 0;
}
int main()
{
    //shell启动时需要从系统中获取环境变量
    //我们的环境变量信息应该从父shell中统一来
    InitEnv();


    while(true)
    {
         //printf("[%s@%s %s]# ",GetUserName(),GetHostName(),GetPwd());
         //1. 打印命令行提示符
         PrintCommandline();

         //2.获取用户输入
         char commandline[COMMAND_SIZE];//定义一个数组
         if(!GetCommandline(commandline,sizeof(commandline)))//如果获取失败continue重新获取
            continue;    
        
         // printf("echo %s\n",commandline);//回显一下我们输入的内容,用作测试

         //3."ls -a -l" -> "ls" "-a" "-l"
         //命令行分析
         if(!CommandParse(commandline))//分析commandline中的命令行
            continue;//只有解析成功后才往下走,否则就继续
         //PrintArgv();

         // 检查别名 直接将commandline替换成别名

         //4.检测并处理内建命令
         if(CheckAndExecBuiltin())
            continue;//若为内建命令就不用创建子进程了,由bash亲自执行
         //5. 执行命令
         Execute();

   }
    return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-04-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
C#开发BIMFACE系列25 服务端API之获取模型数据10:获取楼层对应面积分区列表
在《C#开发BIMFACE系列22 服务端API之获取模型数据7:获取多个模型的楼层信息》中,返回的楼层信息结果中包含了楼层的具体信息,其中包含楼层ID。
张传宁IT讲堂
2019/09/18
5520
C#开发BIMFACE系列25 服务端API之获取模型数据10:获取楼层对应面积分区列表
C#开发BIMFACE系列26 服务端API之获取模型数据11:获取单个面积分区信息
在《C#开发BIMFACE系列25 服务端API之获取模型数据9:获取楼层对应面积分区列表》一文中介绍了如何获取单个模型中单个楼层包含的面积分区列表。有了面积分区列表之后,即可查询单个面积分区的具体信息。
张传宁IT讲堂
2019/09/18
4240
C#开发BIMFACE系列26 服务端API之获取模型数据11:获取单个面积分区信息
C#开发BIMFACE系列18 服务端API之获取模型数据3:获取构件属性
请求地址:GET https://api.bimface.com/data/v2/files/{fileId}/elements/{elementId}
张传宁IT讲堂
2019/09/18
6260
C#开发BIMFACE系列18 服务端API之获取模型数据3:获取构件属性
C#开发BIMFACE系列21 服务端API之获取模型数据6:获取单模型的楼层信息
一个文件/模型中可能包含多个楼层信息,获取楼层信息对于前端页面的动态展示非常有帮助。本篇介绍获取一个文件/模型中可能包含多个楼层信息的详细方法。
张传宁IT讲堂
2019/09/18
7370
C#开发BIMFACE系列21 服务端API之获取模型数据6:获取单模型的楼层信息
C#开发BIMFACE系列19 服务端API之获取模型数据4:获取多个构件的共同属性
在前几篇博客中介绍了一个三维文件/模型包含多个构建,每个构建又是由多种材质组成,每个构建都有很多属性。不同的构建也有可能包含相同的属性。
张传宁IT讲堂
2019/09/18
6550
C#开发BIMFACE系列19 服务端API之获取模型数据4:获取多个构件的共同属性
C#开发BIMFACE系列17 服务端API之获取模型数据2:获取构件材质列表
在上一篇《C#开发BIMFACE系列16 服务端API之获取模型数据1:查询满足条件的构件ID列表》中介绍了获取单文件(模型)的所有构建ID列表。每个构建由多种材质组成,本文介绍获取单个构建ID的材质列表。
张传宁IT讲堂
2019/09/18
4490
C#开发BIMFACE系列17 服务端API之获取模型数据2:获取构件材质列表
C#开发BIMFACE系列22 服务端API之获取模型数据7:获取多个模型的楼层信息
在《C#开发BIMFACE系列21 服务端API之获取模型数据6:获取单模型的楼层信息》中介绍获取单个模型的所有楼层信息。某些场景下根据需要也可以一次性获取多个模型的楼层信息。
张传宁IT讲堂
2019/09/18
1.1K0
C#开发BIMFACE系列22 服务端API之获取模型数据7:获取多个模型的楼层信息
C#开发BIMFACE系列29 服务端API之获取模型数据14:获取图纸列表
一个三维模型中可能包含对应多张二维图纸列表,本篇主要介绍如何获取模型文件对应的图纸列表。
张传宁IT讲堂
2019/09/18
5310
C#开发BIMFACE系列29 服务端API之获取模型数据14:获取图纸列表
C#开发BIMFACE系列16 服务端API之获取模型数据1:查询满足条件的构件ID列表
源文件/模型转换完成之后,可以获取模型的具体数据。本篇介绍根据文件ID查询满足条件的构件ID列表。
张传宁IT讲堂
2019/09/18
9570
C#开发BIMFACE系列16 服务端API之获取模型数据1:查询满足条件的构件ID列表
C#开发BIMFACE系列28 服务端API之获取模型数据13:获取三维视点或二维视图列表
请求地址:GET https://api.bimface.com/data/v2/files/{fileId}/views
张传宁IT讲堂
2019/09/18
5620
C#开发BIMFACE系列28 服务端API之获取模型数据13:获取三维视点或二维视图列表
C#开发BIMFACE系列23 服务端API之获取模型数据8:获取模型链接信息
在Revit等BIM设计工具中可以给模型的某个部位添加链接信息。即类似于在Office Word、Excel 中给一段文字添加本地文件链接或者网址链接等类似功能。例如下面的一个RVT模型种包含了2个链接。
张传宁IT讲堂
2019/09/18
5760
C#开发BIMFACE系列23 服务端API之获取模型数据8:获取模型链接信息
C#开发BIMFACE系列40 服务端API之模型集成
  随着建筑信息化模型技术的发展,越来越多的人选择在云端浏览建筑模型。现阶段的云端模型浏览大多是基于文件级别,一次只可以浏览一个模型文件中的内容。而在工程项目模型设计的过程中,通常由多个设计师协同设计,不同的设计师负责不同的专业领域(例如建筑、结构、水电等)。如果想要在云端浏览整个项目工程,就需要把这些组成部分集成起来一起展示。更近一步,如果要在集成的模型之上进行业务集成的话,就要求在集成过程中对构件按单体,楼层,专业,构件分类,系统类型等进行分类或映射。
张传宁IT讲堂
2021/10/13
5670
C#开发BIMFACE系列15 服务端API之获取模型的View token
在《C#开发BIMFACE系列3 服务端API之获取应用访问凭证AccessToken》中详细介绍了应用程序访问API的令牌凭证。我们知道 Access token 代表自身应用的身份,使用应用的 appkey, secret,通过调用/oauth2/token接口获取。BIMFACE所有的接口调用都需要传递 Access token 。
张传宁IT讲堂
2019/09/18
6410
C#开发BIMFACE系列34 服务端API之模型对比5:获取模型构件对比差异
  BIMFACE平台提供了服务端“获取修改构件属性差异”API,其返回的结果也是一个列表,仅针对修改的构件(不包含新增、删除的构件),是指对于一个修改过的构件ID,其修改前后分别新增、删除了哪些属性,或是属性值发生了变化。
张传宁IT讲堂
2020/03/18
3160
C#开发BIMFACE系列34 服务端API之模型对比5:获取模型构件对比差异
C#开发BIMFACE系列27 服务端API之获取模型数据12:获取构件分类树
BIMFACE官方示例中,加载三维模型后,模型浏览器中左上角默认提供了“目录树”的功能,清晰地展示了模型的完整构成及上下级关系。
张传宁IT讲堂
2019/09/18
9120
C#开发BIMFACE系列27 服务端API之获取模型数据12:获取构件分类树
C#开发BIMFACE系列13 服务端API之获取转换状态
在《C#开发BIMFACE系列12 服务端API之文件转换》中详细介绍了7种文件转换的方法。发起源文件/模型转换后,转换过程可能成功也可能失败。那么在这种情况下就需要查询源文件/模型的转换状态。一共有三种方式可以知道转换是否成功。
张传宁IT讲堂
2019/09/18
4390
C#开发BIMFACE系列12 服务端API之文件转换
在模型成功进行转换后,模型内的BIM信息会在云端进行解析,抽取并结构化入库。这些信息包含:
张传宁IT讲堂
2019/09/18
1.7K0
C#开发BIMFACE系列14 服务端API之批量获取转换状态详情
上一篇《C#开发BIMFACE系列13 服务端API之获取转换状态》中介绍了根据文件ID查询单个文件的转换状态。
张传宁IT讲堂
2019/09/18
6180
C#开发BIMFACE系列32 服务端API之模型对比3:批量获取模型对比状态
  在《C#开发BIMFACE系列31 服务端API之模型对比2:获取模型对比状态》中介绍了根据对比ID,获取一笔记录的对比状态。由于模型对比是在BIMFACE云端进行的,通常需要5~10分钟,在等待对比的过程中还可以发起更多的模型对比,最后通过接口一次性批量获取模型对比状态 。
张传宁IT讲堂
2020/03/18
4250
C#开发BIMFACE系列43 服务端API之图纸拆分
在上一篇博客《C#开发BIMFACE系列42 服务端API之图纸对比》的最后留了一个问题,在常规业务场景下,一个.dwg文件中包含多个图框,如下图
张传宁IT讲堂
2021/10/15
3850
推荐阅读
C#开发BIMFACE系列25 服务端API之获取模型数据10:获取楼层对应面积分区列表
5520
C#开发BIMFACE系列26 服务端API之获取模型数据11:获取单个面积分区信息
4240
C#开发BIMFACE系列18 服务端API之获取模型数据3:获取构件属性
6260
C#开发BIMFACE系列21 服务端API之获取模型数据6:获取单模型的楼层信息
7370
C#开发BIMFACE系列19 服务端API之获取模型数据4:获取多个构件的共同属性
6550
C#开发BIMFACE系列17 服务端API之获取模型数据2:获取构件材质列表
4490
C#开发BIMFACE系列22 服务端API之获取模型数据7:获取多个模型的楼层信息
1.1K0
C#开发BIMFACE系列29 服务端API之获取模型数据14:获取图纸列表
5310
C#开发BIMFACE系列16 服务端API之获取模型数据1:查询满足条件的构件ID列表
9570
C#开发BIMFACE系列28 服务端API之获取模型数据13:获取三维视点或二维视图列表
5620
C#开发BIMFACE系列23 服务端API之获取模型数据8:获取模型链接信息
5760
C#开发BIMFACE系列40 服务端API之模型集成
5670
C#开发BIMFACE系列15 服务端API之获取模型的View token
6410
C#开发BIMFACE系列34 服务端API之模型对比5:获取模型构件对比差异
3160
C#开发BIMFACE系列27 服务端API之获取模型数据12:获取构件分类树
9120
C#开发BIMFACE系列13 服务端API之获取转换状态
4390
C#开发BIMFACE系列12 服务端API之文件转换
1.7K0
C#开发BIMFACE系列14 服务端API之批量获取转换状态详情
6180
C#开发BIMFACE系列32 服务端API之模型对比3:批量获取模型对比状态
4250
C#开发BIMFACE系列43 服务端API之图纸拆分
3850
相关推荐
C#开发BIMFACE系列25 服务端API之获取模型数据10:获取楼层对应面积分区列表
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档