Linux下 Mini-shell的实现(C/C++)

本文介绍了一个用C语言编写的简易shell程序,该程序能在Linux环境下读取并执行通过stdin输入的命令,支持多命令管道及输入输出重定向。

问题描述:

使用C语言在Linux下实现一个mini-shell,该shell从是stdin里面读取命令,然后执行该命令。

输入:

输入包含单行多命令,命令之间使用管道符('|')连接,可以使用输入输出重定向功能,

输入的BNF规范 :

    line ::= command ("|" command)* [redirection]    
    redirection ::= [input_redirection] [output_redirection] | [output_redirection] [input_redirection]
    input_redirecton ::= "<" filename
    output_redirecton ::= ">" filename
    command ::= file_name argument*

输出:

程序本身不输出任何东西,它的exit code就是输入一行命令中最后一个子命令的exit code


源码:

//Written by Openking 2014-11-15
/*Usage: inputs a line of commands connected by '|'
For example: ls -l | less > test.txt
*/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <dirent.h>
#include <stdbool.h>

char buf[150];    // save the input command
char command[20][30];  //save the commands that is splited
int commandNum = 0;    // save the numbers of command
char inputFilename[30];   //save the input file name if it exists
bool isInputExist = 0;    //save the state of existence of input file
char outputFilename[30];   //save the output file name if it exists
bool isOutputExist = 0;    //save the state of existence of output file
char *arg[20];


char * trim(char * src)
{
	int i = 0;
	char *begin = src;
	while(src[i] != '\0')
	{
	    if(src[i] != ' ')
	    {
	        break;
	    }
	    else
	    {
	        begin++;
	    }
	   	i++;
	}
	for(i = strlen(src)-1; i >= 0;  i--)
	{
	    if(src[i] != ' ')
	    {
	        break;
	    }
	    else
	    {
	        src[i] = '\0';
	    }
	}
	return begin;
}

int DealCommandStr()    //analysis the command
{
	int i=0,j=0;
	int p=0,q=0;
	int state = 0;  //state = 0,1,2
	char *str = buf;
	char ch;
	int flag = 0;

	while(ch=*str++)
	{
		if(ch == '|')  //start to save another command
		{
			state = 0;     //command state
			i++;
			j=0;
			continue;
		}
		else if(ch == '<')  //start to save the input file name
		{
			state = 1;         //input file name state
			isInputExist = 1;
			continue;
		}
		else if(ch == '>')
		{
			state = 2;      //output file name state
			isOutputExist = 1;
			continue;
		}
		else
		{
			if(state == 0)   //command state
			{
				command[i][j++] = ch;
			}
			else if(state == 1)  //input file name state
			{
				inputFilename[p++] = ch;
			}
			else    //output file name state
			{
				outputFilename[q++] = ch;
			}
		}
		commandNum = i;   //get the number of commands
	}
	//for(i = 0;i <= commandNum; i++)
	//{
	//	puts(command[i]);
	//}
}

int main()
{
	int i=0,j=0;
	gets(buf);     //get commands
	DealCommandStr();  //deal the input string
	char * str_temp;
	char * readStr;
	char * writeStr;
	pid_t pid[30];
	int pipefd1[2] = {-1,-1};
	int pipefd2[2] = {-1,-1};
	int fdr,fdw;
	int ii=0;
	    /* fork count child process */
	if(commandNum == 0)
	{
        //pid_t fork(void);
        pid[0] = fork();
		if(pid[0] == 0)
		{
			if(isInputExist)
            {
            	fdr = open(trim(inputFilename),O_RDONLY);
            	dup2(fdr, STDIN_FILENO);
            }
            if(isOutputExist)
            {
            	fdw = open(trim(outputFilename),O_WRONLY|O_CREAT|O_TRUNC,0600);
            	dup2(fdw, STDOUT_FILENO);
            }
            /* child process */
            //int execvp(const char *file, char *const argv[]);
            //PureCommandStr(command[0]);
            int iii=0;
            char *buffer = trim(command[0]);
            //puts(buffer);
            while((arg[iii++] = strsep(&buffer," "))!= NULL);
            //setbuf(stdout, NULL);
			//char *a = "ls";
			//char *b[]={"ls","-a"};
			//execvp(b[0],b);
			//printf("%s   %s\n",arg,argv2);
            execvp(arg[0], arg);
            exit(0);
        }
    }
    else
    {
		//printf("command num %d\n",commandNum);
	    for(i = 0; i <= commandNum+1; i++)
	    {
	    	//printf("i num: %d\n",i);
	        /* init pipe file descriptor */
	        pipe(pipefd1);

	        /* fork child i */
	        pid[i] = fork();
	        //printf("pid num: %d\n",pid[i]);

	    	if(pid[i] == 0)
	    	{
	            /* child i */

	            //int dup2(int oldfd, int newfd);
	            if(i == 0)
	            { /* the first child */
	            	close(pipefd1[0]);
	                if(isInputExist)
	                {
	                	fdr = open(trim(inputFilename),O_RDONLY);
	                	dup2(fdr, STDIN_FILENO);
	                }
	                dup2(pipefd1[1], STDOUT_FILENO);
	                close(pipefd1[1]);

	            }
	            else if(i == commandNum)
	            { /* the last child */
	            	dup2(pipefd2[0], STDIN_FILENO);
	                close(pipefd2[1]); /* close prev process end of write */
	                close(pipefd2[0]); /* close curr process end of read */

	                if(isOutputExist)
	                {
	                	fdw = open(trim(outputFilename),O_WRONLY|O_CREAT|O_TRUNC,0600);
	                	dup2(fdw, STDOUT_FILENO);
	                }
	            }
	            else
	            {
	            	dup2(pipefd1[1], STDOUT_FILENO);

	            	close(pipefd1[0]);
	                close(pipefd1[1]);

	                dup2(pipefd2[0], STDIN_FILENO);

	                close(pipefd2[0]);
	                close(pipefd2[1]);
	            }
	            //int execvp(const char *file, char *const argv[]);
	            //PureCommandStr(command[i]);
				//char *argv2 = command[i];
				int iii=0;
            	char *buffer = trim(command[i]);
            	//puts(buffer);
	            while((arg[iii++] = strsep(&buffer," "))!= NULL);
				//printf("%s   %s\n",arg,argv2);
				execvp(arg[0], arg);
				//printf("i num: %d\n",i);
	        }

	        if(i!=0)
		    {
		      	close(pipefd2[0]);
		      	close(pipefd2[1]);
		    }
			  	pipefd2[0]=pipefd1[0];
			  	pipefd2[1]=pipefd1[1];
		}
	}

    for(i = 0; i <=commandNum; i++)
    {
        //pid_t waitpid(pid_t pid, int *status, int options);
        waitpid(pid[i], NULL, 0);
    }
}

测试:我们使用命令:

ls -l | less > test.txt


在文件test.txt可以看到结果:

total 32
-rw------- 1 openking openking    33  1月 18 13:22 1.txt
-rw-rw-r-- 1 openking openking  8294 11月 21 16:42 shell.cc
-rwxrwxr-x 1 openking openking 13471  1月 18 13:21 shell.o
-rw------- 1 openking openking     0  1月 18 13:24 test.txt


building 'flash_attn_2_cuda' extension creating build/temp.linux-x86_64-cpython-310/csrc/flash_attn creating build/temp.linux-x86_64-cpython-310/csrc/flash_attn/src g++ -pthread -B /home/yxx/miniconda3/envs/simpler_ori/compiler_compat -Wno-unused-result -Wsign-compare -DNDEBUG -fwrapv -O2 -Wall -fPIC -O2 -isystem /home/yxx/miniconda3/envs/simpler_ori/include -fPIC -O2 -isystem /home/yxx/miniconda3/envs/simpler_ori/include -fPIC -I/tmp/pip-install-ru5uufkn/flash-attn_d835e5ef515c4ef1ae25b02f8e2df32b/csrc/flash_attn -I/tmp/pip-install-ru5uufkn/flash-attn_d835e5ef515c4ef1ae25b02f8e2df32b/csrc/flash_attn/src -I/tmp/pip-install-ru5uufkn/flash-attn_d835e5ef515c4ef1ae25b02f8e2df32b/csrc/cutlass/include -I/home/yxx/miniconda3/envs/simpler_ori/lib/python3.10/site-packages/torch/include -I/home/yxx/miniconda3/envs/simpler_ori/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -I/home/yxx/miniconda3/envs/simpler_ori/lib/python3.10/site-packages/torch/include/TH -I/home/yxx/miniconda3/envs/simpler_ori/lib/python3.10/site-packages/torch/include/THC -I/home/yxx/miniconda3/envs/simpler_ori/include -I/home/yxx/miniconda3/envs/simpler_ori/include/python3.10 -c csrc/flash_attn/flash_api.cpp -o build/temp.linux-x86_64-cpython-310/csrc/flash_attn/flash_api.o -O3 -std=c++17 -DTORCH_API_INCLUDE_EXTENSION_H -DPYBIND11_COMPILER_TYPE=\"_gcc\" -DPYBIND11_STDLIB=\"_libstdcpp\" -DPYBIND11_BUILD_ABI=\"_cxxabi1011\" -DTORCH_EXTENSION_NAME=flash_attn_2_cuda -D_GLIBCXX_USE_CXX11_ABI=0 In file included from /tmp/pip-install-ru5uufkn/flash-attn_d835e5ef515c4ef1ae25b02f8e2df32b/csrc/cutlass/include/cutlass/numeric_types.h:42, from csrc/flash_attn/flash_api.cpp:13: /tmp/pip-install-ru5uufkn/flash-attn_d835e5ef515c4ef1ae25b02f8e2df32b/csrc/cutlass/include/cutlass/bfloat16.h:48:10: fatal error: cuda_bf16.h: No such file or directory 48 | #include <cuda_bf16.h> | ^~~~~~~~~~~~~ compilation terminated. error: command '/usr/bin/g++' failed with exit code 1 [end of output] note: This error originates from a subprocess, and is likely not a problem with pip. ERROR: Failed building wheel for flash-attn Running setup.py clean for flash-attn Failed to build flash-attn ERROR: Failed to build installable wheels for some pyproject.toml based projects (flash-attn)在安装flash-attn过程中出现了上述报错,是什么原因
最新发布
07-02
<think>我们正在处理一个关于安装flash-attn时遇到的构建错误。用户报告了两个错误: 1. `error:command 'g++' failedwith exitstatus1` 2. `fatalerror:cuda_bf16.h: Nosuch fileor directory` 根据错误信息,第二个错误很可能是导致第一个错误的原因。因为编译器在尝试包含`cuda_bf16.h`头文件时找不到该文件,从而导致编译失败。 ###原因分析1.**缺少CUDA Toolkit头文件**:`cuda_bf16.h`是CUDA Toolkit的一部分,通常位于CUDA安装目录的`include`子目录中。这个错误表明系统没有找到这个头文件,可能的原因包括:-CUDAToolkit没有正确安装。-安装的CUDA版本太旧,不包含这个头文件(因为`cuda_bf16.h`是在CUDA11.0或更新版本中引入的)。-环境变量(如`CUDA_HOME`或`PATH`)没有正确设置,导致编译器无法定位CUDA的头文件和库。2.**环境变量配置问题**:在编译过程中,编译器需要知道CUDAToolkit的安装位置。如果环境变量`CUDA_HOME`或`CUDA_PATH`没有设置,或者设置不正确,就会导致找不到CUDA的头文件。###解决方案####步骤1:确认CUDA Toolkit的安装首先,请确认您的系统已经安装了CUDA Toolkit,并且版本至少为11.0。可以通过以下命令检查:```bashnvcc --version``` 或者查看CUDA版本:```bashcat/usr/local/cuda/version.txt```如果未安装CUDA Toolkit,或者版本低于11.0,请先安装或升级CUDA Toolkit。可以从NVIDIA官方网站下载并安装合适版本的CUDA Toolkit。####步骤2:设置环境变量确保环境变量`CUDA_HOME`(或`CUDA_PATH`)已正确设置,并指向CUDA的安装目录(例如`/usr/local/cuda`)。同时,确保`PATH`环境变量中包含`$CUDA_HOME/bin`。 您可以通过以下命令临时设置环境变量(假设CUDA安装在`/usr/local/cuda`): ```bashexport CUDA_HOME=/usr/local/cudaexportPATH=$CUDA_HOME/bin:$PATHexport LD_LIBRARY_PATH=$CUDA_HOME/lib64:$LD_LIBRARY_PATH``` 然后尝试重新安装flash-attn。为了永久设置这些环境变量,可以将上述导出命令添加到您的shell配置文件(如`~/.bashrc`或`~/.zshrc`)中,然后执行`source~/.bashrc`(或相应的配置文件)。####步骤3:检查头文件位置确认`cuda_bf16.h`文件确实存在于您的CUDA安装目录中。例如,检查: ```bashls $CUDA_HOME/include/cuda_bf16.h``` 如果该文件不存在,可能是CUDA Toolkit安装不完整。考虑重新安装CUDAToolkit。####步骤4:安装flash-attn时指定CUDA路径在安装flash-attn时,您可以通过设置`CUDA_HOME`环境变量来明确指定CUDA的路径。例如: ```bashCUDA_HOME=/usr/local/cuda pipinstall flash-attn``` 或者,如果使用源码安装,可以尝试: ```bashCUDA_HOME=/usr/local/cuda pythonsetup.pyinstall``` ####步骤5:安装依赖项确保您已经安装了flash-attn所需的所有依赖项。根据其文档,可能需要安装PyTorch(与CUDA版本匹配)、packaging等。建议在安装flash-attn之前,先安装PyTorch(通过官方命令安装)。####步骤6:使用Docker(可选)如果上述步骤仍然无法解决问题,考虑使用NVIDIA官方提供的PyTorchDocker镜像,这些镜像已经配置好了CUDA环境。例如: ```bashdocker run--gpus all-it--rmnvcr.io/nvidia/pytorch:23.05-py3``` 然后在容器内安装flash-attn。 ###补充说明根据参考的站内引用[^1],有时权限问题也可能导致构建失败,但本错误更可能是由于缺少头文件或环境配置问题。如果遇到权限问题,可以尝试使用`sudo`(但需谨慎)或调整临时目录权限。###相关问题1.如何检查系统中安装的CUDA版本? 2.在Linux系统中如何正确设置CUDA环境变量? 3.如何解决在Docker容器中安装CUDA相关库的问题?4.安装flash-attn需要满足哪些系统要求?[^1]:引用自站内关于构建失败原因的描述,但本例中的错误更可能是由于缺少CUDA头文件或环境配置问题。</think>### 安装 flash-attn 失败的原因与解决方案 #### 错误原因分析 1. **`fatal error: cuda_bf16.h: No such file or directory`** - 缺少 CUDA bfloat16 头文件,表明 CUDA Toolkit **未正确安装**或**版本过低**(要求 CUDA 11.0+) - 环境变量 `CUDA_HOME` 未配置,导致编译器无法定位 CUDA 头文件路径[^1] 2. **`error: command 'g++' failed with exit code 1`** - 上述头文件缺失导致 C++ 编译链中断 - 可能伴随其他依赖缺失(如 g++ 编译器、PyTorch-CUDA 版本不匹配) --- #### 完整解决方案 ##### 步骤 1: 验证 CUDA 环境 ```bash # 检查 CUDA 版本 (要求 ≥11.0) nvcc --version cat /usr/local/cuda/version.txt # 确认头文件存在 ls /usr/local/cuda/include/cuda_bf16.h # 若不存在需重装 CUDA ``` ##### 步骤 2: 修复 CUDA 配置 ```bash # 设置环境变量 (根据实际安装路径修改) export CUDA_HOME=/usr/local/cuda # 常见路径 export PATH=$CUDA_HOME/bin:$PATH export LD_LIBRARY_PATH=$CUDA_HOME/lib64:$LD_LIBRARY_PATH # 永久生效:写入 ~/.bashrc echo "export CUDA_HOME=/usr/local/cuda" >> ~/.bashrc source ~/.bashrc ``` ##### 步骤 3: 安装依赖库 ```bash # 安装 CUDA 开发包 (Ubuntu 示例) sudo apt install cuda-toolkit-11-8 cuda-nvcc-11-8 # 匹配你的 CUDA 版本 # 安装编译工具链 sudo apt install build-essential g++ python3-dev ``` ##### 步骤 4: 重装 flash-attn ```bash # 确保 PyTorch 与 CUDA 版本匹配 pip install torch --extra-index-url https://download.pytorch.org/whl/cu118 # 示例 CUDA 11.8 # 指定 CUDA_HOME 安装 flash-attn CUDA_HOME=/usr/local/cuda pip install flash-attn --no-cache-dir ``` ##### 步骤 5: 权限修复(若出现 `/tmp` 写入错误) ```bash sudo chmod 777 /tmp # 临时解决方案 # 或指定临时目录 export TMPDIR=/your/writable/path ``` --- #### 关键验证点 1. **CUDA 与 PyTorch 版本兼容** ```python import torch print(torch.__version__, torch.cuda.is_available()) # 应返回 True ``` 2. **头文件路径检查** ```bash echo $CUDA_HOME # 必须返回有效路径 find $CUDA_HOME -name cuda_bf16.h # 应找到文件 ``` > ⚠️ 若仍失败,尝试源码安装: > ```bash > git clone https://github.com/Dao-AILab/flash-attention > cd flash-attention && python setup.py install > ``` --- ### 相关问题 1. 如何检查 PyTorch 与 CUDA 的兼容性? 2. 在 Docker 容器中安装 CUDA 依赖有哪些注意事项? 3. 如何为不同的 CUDA 版本管理多个环境? 4. 遇到 `nvcc fatal : Could not open output file` 错误时如何解决权限问题?[^1] [^1]: 引用自用户提供的站内参考,涉及权限问题导致编译失败的情况。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值