进程与文件系统
cd ../ cd / 之类的命令
让bash自己执行的命令,称之为内建命令/内置命令。
几乎所有的环境变量的命令,都是内建命令。
在Linux中,内建命令是指已经集成在shell程序中的命令,它们的执行不需要加载外部程序,可以直接在命令行上运行。这些内部命令的执行速度通常比外部命令更快,因为它们不需要去磁盘加载外部程序。
例如,在Bash shell中,常见的内部命令包括:
- cd:切换当前工作目录
- echo:输出文本或变量内容
- pwd:打印当前工作目录路径
- export:设置环境变量
- alias:创建一个命令别名
- history:查看执行过的命令历史记录
- source:执行指定文件中的命令
可以使用内建命令的好处是它们快速,并且可以与系统的环境变量和其他属性进行交互,并且更容易维护。
一般来说,与环境变量有关的命令都是内建命令,一般用户自定义的环境变量,在bash中要用户自己来进行维护,不要用一个经常被覆盖的缓冲区来保存环境命令。让它能够持续保存下来!
chdir()函数是C语言和C++中的一个标准库函数,用于改变当前工作目录。这个函数位于头文件<unistd.h>中。
函数原型如下:
int chdir(const char *path);
其中,path为要改变工作目录为的目录路径。如果改变成功返回0,如果失败返回-1。
下面是一个使用chdir()函数的简单例子:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main() {
int ret;
char *cur_dir = NULL;
/* 获取当前路径 */
cur_dir = getcwd(cur_dir, 0);
printf("当前工作目录:%s\n", cur_dir);
free(cur_dir);
/* 改变当前目录 */
ret = chdir("/");
if (ret == -1) {
printf("chdir错误,错误号:%d\n", errno);
return -1;
}
printf("当前工作目录:%s\n", getcwd(NULL, 0));
return 0;
}
这个程序首先调用getcwd()函数获取当前工作目录,并输出。然后使用chdir()函数将当前工作目录改为根目录。再次调用getcwd()函数获取当前工作目录,并输出。
这个程序成功地将当前工作目录改为了根目录。
需要注意的是,chdir()函数并不能改变其他进程的工作目录。如果需要改变其他进程的工作目录,常常需要使用其他的通信方式,例如使用管道、Socket等。
文件描述符
文件读写
在Linux中,open和write和close是常用的文件操作函数,可以用于打开、写入和关闭文件。
1. open函数:open函数用于打开文件。函数原型如下:
#include <fcntl.h>
int open(const char *path, int flags, mode_t mode);
其中,path是要打开的文件路径+文件名,flags是打开文件的方式,mode是文件权限参数。常见的打开方式包括:
- O_RDONLY:只读模式打开文件
- O_WRONLY:只写模式打开文件
- O_RDWR:可读可写模式打开文件
- O_APPEND:追加模式打开文件
- O_WRONLY 和 O_CREAT不会清空原本的文件内容
- O_CREAT:如果文件不存在,则创建文件
需要在先将写入操作进行,然后再进行以下操作
- 0_TRUNC清空已有文件内容
例如,使用O_WRONLY方式打开文件:
int fd = open("myfile.txt", O_WRONLY|O_CREAT|O_TRUNC, 0644);
注意:
在表示权限的时候要注意系统自带的掩码,它会屏蔽掉你不想要的权限;如需修改系统自带的掩码,可以使用umask()函数,系统采用就近原则。默认情况下,掩码初始值是022
,这表示文件默认权限为666 & ~022
,即文件默认权限是644
,目录默认权限是777 & ~022
,即目录默认权限是755
。
mode_t umask(mode_t mask);
umask的使用案例:
mode_t old_mask = umask(0); // 保存旧的掩码值
umask(0022); // 设置新的掩码值
2. write函数用于向已经打开的文件中写入数据。函数原型如下:
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
其中,fd是已经打开的文件描述符,buf是要写入的数据的缓冲区地址,count是要写入的数据大小。例如,写入数据到文件:
char* str = "Hello, world!";
ssize_t num = write(fd, str, strlen(str));
3. read函数:read函数用于从已经打开的文件中读取数据。函数原型如下:
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
其中,fd是已经打开的文件描述符,buf是要读取数据的缓冲区地址,count是要读取的数据大小。例如,从文件中读取数据:
char buffer[1024];
//这里我们无法做到按行进行读取,这里是进行整体读取
ssize_t numbytes = read(fd, buffer, sizeof(buffer) - 1);
使用系统接口来进行IO的时候,一定要注意\0问题
4. close函数:close函数用于关闭文件。函数原型如下:
#include <unistd.h>
int close(int fd);
其中,fd是已经打开的文件描述符。例如,关闭文件:
close(fd);
需要注意的是,在编程中使用这些函数时,需要确保文件打开和关闭的正确性,以及写入数据的大小和实际需要写入的数据是否一致。
5. lseek()是在Linux/Unix系统中用于改变文件读写指针位置(文件偏移量)的系统调用。在打开文件时,对每个进程都会创建一个文件表结构,其中包含有文件偏移量和文件状态标志等信息。lseek()可以操作该文件偏移量,一般用于随机访问文件。
lseek()函数的定义为:
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
其中,参数fd是文件描述符,表示要操作的文件;偏移量offset表示要将文件指针移到的位置,可以是正数、负数或零;参数whence表示移动的基准位置,它可以取以下三种值:
- SEEK_SET:从文件开头开始偏移,即偏移量为文件起始位置加上offset。
- SEEK_CUR:从当前文件位置开始偏移,即偏移量为当前文件位置加上offset。
- SEEK_END:从文件末尾开始偏移,即偏移量为文件长度加上offset。
如果lseek()调用成功,则会返回移动后的文件偏移量;如果发生错误,则返回-1,并设置全局变量errno存放错误码。
使用系统接口来进行IO的时候,一定要注意 \0 的问题
我们所谓的IO类read,write函数,本质是拷贝函数(用户空间和内核空间进行数据的来回拷贝)。
什么时候刷新到磁盘中指定的位置,由OS自主决定
我们使用OS的本质:都是通过进程的方式进行OS的访问的。
在进程的眼中,它只能看到文件,对它来说一切都是struct_file,所以才有Linux中的"一切皆文件"
进程中,文件描述符的分配规则:在文件描述符中,最小的,没有被使用的数组元素,分配给新文件。
文件描述符fd(open)返回值的本质就是数组下标,实际上就是放入到了文件描述符表中
系统默认打开的这三个文件占用了0,1,2的下标,我们打开文件只能占用3以及以后的坐标。
标准输出和标准错误都会向显示器打印,但是其实是不一样的
进程中,文件描述符发分配规则:在文件描述符表中,找到最小且没有被使用的数组元素,分配给新文件
重定向
重定向原理
在上层无法感知的情况下,在OS内部,更改进程对应的文件描述符表中,特定下标的指向!!!
在Linux中,重定向是一种将命令的输入或输出从标准位置(比如屏幕或键盘)更改为其他位置的方法。有两种常见类型的重定向:
- 标准输出重定向:将命令的输出从标准输出(通常是屏幕)发送到文件中或向其他进程传递。
- 标准输入重定向:将命令的输入从标准输入(通常是键盘)更改为来自文件或其他进程的输出。
- 在Linux中,标准错误(stderr)是指在命令执行过程中产生的错误信息。与标准输出不同,标准错误通常默认打印到屏幕上,但是我们可以使用标准错误重定向将其重定向到其他位置,以便更好地进行错误处理。
将命令输出到文件
使用 > 符号可以将命令的标准输出重定向到一个文件中。例如,我们可以用以下命令将ls命令的输出保存到一个文件中:
ls > file.txt
1. 将命令输出追加到文件末尾
使用 >> 符号可以将命令的标准输出追加到一个文件的末尾。例如,我们可以用以下命令将ls命令的输出追加到一个文件的末尾:
ls >> file.txt
2. 将文件作为命令的输入
使用 < 符号可以将文件作为命令的输入。例如,我们可以用以下命令将一个文件的内容作为输入传递给cat命令:
cat < file.txt
3. 将命令错误输出重定向到文件
使用 2> 符号可以将命令的标准错误输出重定向到一个文件中。例如,我们可以用以下命令将错误输出保存到一个文件中:
2>error.log
OS一般如何让用户给自己传递标志位的?
我们可以用一个bit位表示一个标志位,这样一个int类型至少可以传递32个标记位,都是够用了,其实就是位图。
缓冲区:
a、显示器采用的刷新策略:行缓冲
普通文件采用的刷新策略:全缓冲
b、为什么要有缓冲区?
节省调用者的时间 系统调用也是要花费时间的!
c、缓冲区在哪个位置?
在你进行fopen调用的时候,会得到返回的FILE结构体的指针,缓冲区就在这个指针所指向的结构体当中!!!