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调用的对应文件,必须要有对应对应的标识符支持

相关推荐
齐潇宇3 小时前
Zabbix 7 概述与配置
linux·zabbix·监控告警
裴东青5 小时前
10-实战:RuoYi-Cloud的自动化发布
运维·ci/cd·自动化
江公望5 小时前
Ubuntu htop命令,10分钟讲清楚
linux·服务器
哎呦,帅小伙哦5 小时前
Linux 时间:从原子钟到 clock_gettime 的每一面
linux·运维·服务器
sxgzzn5 小时前
新能源场站数智化转型:基于数字孪生与AI的智慧运维管理平台解析
大数据·运维·人工智能
张小姐的猫5 小时前
【Linux】多线程 —— 线程互斥
linux·运维·服务器·c++
CodeMartain6 小时前
Dify Windows 原生部署(无 Docker、纯本地)
运维·docker·容器
xxx1x1x6 小时前
极客向:DLL/运行库故障的底层逻辑与自动化修复方案
运维·自动化·dll文件·dll·dll修复·dll缺失·dll一键修复
YuanDaima20486 小时前
Linux 进阶运维与 AI 环境实战:进程管理、网络排错与 GPU 监控
linux·运维·服务器·网络·人工智能
lolo大魔王7 小时前
Linux 数据文件处理实战:排序、搜索、压缩、归档一站式详解
linux·运维·服务器