linux之shell的进阶补充和基础IO流的介绍

1.内建命令的实现

先前基础版中没有对cd这些内建命令的设置,这些内建命令是在父进程中实行的,说白了就是在父进程中调用对应的OS接口

1.cd

复制代码
//移动到path路径
int chdir(const char*path);

if(argv[0] == "cd")
{
    if(argc == 2)
    {
        chdir(argv[1]);
        //lastcode是错误码
        lastcode = 0;
    }
    else
    {
        //应该要分类讨论的
        lastcode = 1;
    }
return true;

补充一点知识:

(1)char* getcwd(char*buf,int size);返回值就是buf的地址,buf存当前路径,size是buf的大小后最大存储空间

(2)putenv("xx=xxx");xx已存在时就覆盖原有的环境变量,没有就创建一个新的,=号是一定要存在的。

(3)有些指令即是内置指令,也是外带指令,也就是一个指令即可能只是shell中的一个函数,也可能在/usr/bin/目录下留有可执行文件。

2.echo

(1)$? ,打印lastcode,其他情况打印对应环境变量名的值

(2)直接打印

复制代码
if(gargv[0] =="echo")
{
    if(gargc == 2)
{
    if(gargv[1][0] == '$')
{
    if(gargv[1][1] == '?')
{    
    printf("%d\n", lastcode);
    lastcode = 0;
}
    else
    {
    //此处还要处理$环境变量名的情况
    }
}
    else
{
    printf("%s\n", gargv[1]);
    lastcode = 0;
}
}
    else
{
    lastcode = 3;
}

3.生成环境变量表

此处我们简化处理使用父进程的环境变量表即可(只是模拟,并没有实际使用)

cpp 复制代码
void InitEnv()
{
extern char **environ;
int index = 0;
while(environ[index])
{
genv[index] = (char*)malloc(strlen(environ[index])+1);
strncpy(genv[index], environ[index], strlen(environ[index])+1);
index++;
}
genv[index] = nullptr;
}

2.基础IO(才是核心)

1.复习c语言与一些之前的知识

操作文件就是操作其的内容与属性。文件由进程打开,因此对文件的操作就是进程对文件的操作。

磁盘的管理者只有OS,我们调用库函数的本质就是间接使用OS提供的接口。

同一时间下被打开的文件可能有很多个,因此OS是采用先描述再组织的方式管理当前所有被打开的文件。

文件分两种:

内存级(已经被打开)文件2.磁盘(未被打开)级文件,后面先介绍内存级文件

函数:

复制代码
fwrite(const void *ptr,size_t size,size_t nmemb,FILE*stream);
//将ptr中size*nmemmb大小的数据存入stream中

feof(FILE*stream);
//判断stream指向的文件是否走到结尾

size_t fread(const void *ptr,size_t size,size_t nmemb,FILE*stream);
返回值是返回nmemb的值

w,a,r,的本质:

复制代码
w:文件会先被清空
//如: > 重定向就是将右边的文件用类似于w的形式打开
a:往先前的文件数据中追加
//如:  >>重定向就是将右边的文件用类似于a的形式打开
r+:以既能写有能读的方式打开文件,但读写共用同一个光标

3.系统的IO调用

复制代码
int open(const char* pathname,int flags);
int open(const char* pathname,int flags,mode_t mode);

flags是一种标识符,例:

采用&来区分是否使用了这个标识符,使用|来同时使用多种标识符。

复制代码
//二进制位0001
int a = 1;
//二进制位0010
int b = 2;
//二进制位0100
int c = 4;
//....

void func(int flags)
{
if(flags&(1 << 0))cout << "1号标识符";
if(flags&(1 << 1))cout << "2号标识符";
if(flags&(1 << 2))cout << "3号标识符";
//.....
}

int main()
{
    func(a | b | c);    
    return 0
}

当filename是一个新文件时,要给其加上初始化的权限设置(会被权限掩码(umask)操作),也就是插入mode参数(例:0666值)来初始化文件权限。

标识符类型:

O_CREAT 打开文件

O_WRONLY 往文件中写入

O_TRONC 清空文件

O_APPEND 追加内容

O_RDONLY 以读的方式打开文件(二进制形式)

复制代码
int close(int fd);
fd就是open的返回值,用于关闭对应的文件

ssize_t write(int fd,const void* buf,size_t count);
把buf前count个字符写入fd对应的文件中,返回值为成功输入的字符数

使用strlen统计buf大小时不用+1,即不用写入/0,因为文件写入时不认识c语言的转义字符。

buf的类型为void*,说明其可以传入任意类型的数据,根本上来讲就是OS其实不管心我们传进来的数据类型,所有的数据本身都是以二进制的方式写入的,而显示屏又叫字符显示屏,因此传入的数据中只有才能正常显示,其余的都是乱码。

因此语言层面上的文本写入或二进制写入的本质都是调用write的封装罢了,实现文本写入的方式为:

复制代码
int func(int a)
{
    char buf[16];
    //提前写成字符的形式了
    sprintf(buf,siseof(buf),a);
    write(fd,buf,strlen(buf));
}

read

复制代码
ssize_t read(int fd,void * buf,size_t count);

将fd对应文件的内容写到buf中,最大写入大小为count,返回值>0时表示写入的字符个数,=0表示已经读取到文件末尾,<0代表读取失败。

read和write调用的对应文件,必须要有对应对应的标识符支持

相关推荐
志栋智能2 小时前
运维超自动化:构建弹性IT架构的关键支撑
运维·服务器·网络·人工智能·架构·自动化
草莓熊Lotso3 小时前
Vibe Coding 时代:LangChain 与 LangGraph 全链路解析
linux·运维·服务器·数据库·人工智能·mysql·langchain
代码AI弗森8 小时前
一文理清楚“算力申请 / 成本测算 / 并发评估”
java·服务器·数据库
蜡台9 小时前
Python包管理工具pip完全指南-----2
linux·windows·python
^—app5668669 小时前
游戏运存小启动不起来临时解决方法
运维·服务器
Ujimatsu10 小时前
虚拟机安装Debian 13.x及其常用软件(2026.4)
linux·运维·ubuntu
千百元10 小时前
zookeeper启不来了
linux·zookeeper·debian
志栋智能10 小时前
超自动化安全:构建智能安全运营的核心引擎
大数据·运维·服务器·数据库·安全·自动化·产品运营
AnalogElectronic11 小时前
linux 测试网络和端口是否连通的命令详解
linux·网络·php