惊!printf 不往屏幕输?都是 fd 在搞鬼!爆肝拆解 Linux 文件描述符 + 重定向底层,学会直接在终端横着走

文 章 目 录

  • [一、文 件](#一、文 件)
    • [1、基 础 知 识](#1、基 础 知 识)
    • [2、C 文 件 接 口](#2、C 文 件 接 口)
      • [(1)代 码 示 例](#(1)代 码 示 例)
      • [(2)当 前 路 径](#(2)当 前 路 径)
      • [(3)文 件 权 限](#(3)文 件 权 限)
      • (4)w
      • (5)a
      • [(6)三 个 输 入 输 出 流](#(6)三 个 输 入 输 出 流)
    • [3、分 开 显 示 stdout 和 stderr](#3、分 开 显 示 stdout 和 stderr)
    • [4、基 础 知 识](#4、基 础 知 识)
  • [二、访 问 文 件 的 本 质](#二、访 问 文 件 的 本 质)
  • [三、重 定 向](#三、重 定 向)
    • [1、文 件 描 述 符 的 分 配 规 则](#1、文 件 描 述 符 的 分 配 规 则)
    • [2、重 定 向 的 原 理](#2、重 定 向 的 原 理)
    • 3、dup2
    • [4、输 入 重 定 向](#4、输 入 重 定 向)
    • [5、追 加 重 定 向](#5、追 加 重 定 向)
    • [6、输 入 重 定 向](#6、输 入 重 定 向)
    • [7、printf 与 fprintf](#7、printf 与 fprintf)
  • [四、总 结](#四、总 结)

💻作 者 简 介:曾 与 你 一 样 迷 茫,现 以 经 验 助 你 入 门 Linux。

💡个 人 主 页:@笑口常开xpr 的 个 人 主 页

📚系 列 专 栏:Linux 探 索 之 旅:从 命 令 行 到 系 统 内 核

✨代 码 趣 语:当 0、1、2 先 占 满 文 件 描 述 符 的 "插 槽",open 总 会 寻 着 最 小 的 空 缺 安 家 - - - 每 个 fd 的 数 字,都 是 进 程 与 文 件 牵 手 的 "门 牌 号 码",藏 着 读 写 消 息 的 去 向。

💪代 码 千 行,始 于 坚 持,每 日 敲 码,进 阶 编 程 之 路。

📦gitee 链 接:gitee

Linux 初 学 者 常 困 惑:会 用 > 重 定 向 却 不 懂 原 理,知 道 printf 输 出 却 不 明 其 与 "文 件" 的 关 联,对 0、1、2 文 件 描 述 符 更 是 茫 然。这 些 疑 问 的 核 心,正 是 "进 程 与 文 件 的 交 互 逻 辑" - - - 本 文 以 实 操 + 原 理 为 核 心,从 "文 件 = 内 容 + 属 性" 切 入,讲 清 C 库 / 系 统 调 用 用 法,拆 解 文 件 描 述 符 规 则 与 重 定 向 本 质,搭 配 代 码 截 图 帮 你 打 通 "命 令 - 代 码 - 内 核" 链 路。


一、文 件

1、基 础 知 识

  1. 文 件 = 内 容 + 属 性
  2. 文 件 分 为 打 开 的 文 件 和 没 有 打 开 的 文 件。进 程 打 开 的 文 件,没 打 开 的 文 件 存 储 在 磁 盘 上,没 有 打 开 的 文 件 非 常 多。本 质 上 是 研 究 进 程 和 文 件 的 关 系,要 快 速 的 对 文 件 进 行 增 删 查 改。
  3. 文 件 想 要 被 打 开 首 先 应 该 被 加 载 到 内 存。
  4. 进 程 :打 开 文 件 = 1:n,一 个 进 程 可 以 打 开 多 个 文 件。操 作 系 统 内 部 一 定 存 在 大 量 的 被 打 开 的 文 件。操 作 系 统 要 管 理 被 打 开 的 文 件,先 描 述,再 组 织。
  5. 在 Linux 内 核 中,一 个 被 打 开 的 文 件 都 必 须 有 自 己 的 文 件 打 开 对 象,包 含 文 件 的 很 多 属 性。

2、C 文 件 接 口

C 语 言 文 件 操 作

(1)代 码 示 例

javascript 复制代码
#include<stdio.h>
#include<unistd.h>
int main()
{
    printf("pid:%d\n",getpid());
    //打开文件的路径和文件名,默认在当前路径下创建一个文件
    FILE* pf = fopen("test.txt","w");
    if(pf == NULL)
    {
        perror("fopen fail");
        return 1;
    }
    fclose(pf);
    sleep(100);
    return 0;
}

(2)当 前 路 径

当 前 路 径 指 的 是 进 程 的 当 前 路 径 cwd,如 果 更 改 了 当 前 进 程 的 cwd,就 可 以 把 文 件 新 建 到 其 他 目 录。

可 以 使 用 ll /proc/进 程 的 PID 来 查 看 进 程 的 当 前 路 径。


chdir

更 改 进 程 的 工 作 目 录。

在 上 面 的 代 码 中 添 加 chdir("/home/xpr/linux"); 可 以 更 改 进 程 的 路 径。


(3)文 件 权 限


(4)w

将 字 符 写 入 文 件。如 果 没 有 文 件 则 会 创 建 文 件,如 果 文 件 有 内 容 则 会 清 空。


fwrite

将 字 符 写 入 到 文 件 中。

javascript 复制代码
#include<stdio.h>
#include<unistd.h>
#include<string.h>
int main()
{
    printf("pid:%d\n",getpid());
    //打开文件的路径和文件名,默认在当前路径下创建一个文件
    FILE* pf = fopen("test.txt","w");
    if(pf == NULL)
    {
        perror("fopen fail");
        return 1;
    }
    const char* str = "hello linux";
    fwrite(str,strlen(str),1,pf);
    fclose(pf);
    return 0;
}

这 里 strlen 不 需 要 加 1 原 因 是 因 为 如 果 加 1 会 出 现 乱 码,如 下 图 所 示。字 符 串 以 \0 结 尾 是 C 语 言 的 规 定,和 文 件 没 有 关 系。

strlen + 1

strlen + 1 会 在 文 件 中 出 现 ^@,这 个 字 符 就 是 \0


echo 及 输 入 重 定 向

类 似 的,echo 的 输 入 重 定 向 和 w 类 似,如 果 没 有 文 件 则 会 创 建,文 件 有 内 容 则 会 清 空。


(5)a

在 文 件 结 尾 追 加 字 符 串,如 果 没 有 文 件 则 会 创 建 文 件。

javascript 复制代码
#include<stdio.h>
#include<unistd.h>
#include<string.h>
int main()
{
    printf("pid:%d\n",getpid());
    //打开文件的路径和文件名,默认在当前路径下创建一个文件
    FILE* pf = fopen("test.txt","a");
    if(pf == NULL)
    {
        perror("fopen fail");
        return 1;
    }
    const char* str = "hello linux";
    fwrite(str,strlen(str)+1,1,pf);
    fclose(pf);
    return 0;
}

echo 及 输 出 重 定 向


(6)三 个 输 入 输 出 流

所 有 的 语 言 在 启 动 时 默 认 都 会 打 开 对 应 的 设 备 文 件,原 因 是 因 为 电 脑 开 机 时 就 会 打 开 显 示 器 和 键 盘,编 写 代 码 时 使 用 键 盘 输 入,用 显 示 器 显 示。C 语 言 的 3 个 输 入 输 出 流。C 程 序 默 认 在 启 动 时 会 打 开 三 个 标 准 输 入 输 出 流(文 件)。
所 有 的 语 言 对 于 文 件 的 操 作 都 包 括 文 件 描 述 符 fd

stdin :键 盘
stdout :显 示 器 文 件
stderr :显 示 器 文 件


3、分 开 显 示 stdout 和 stderr

javascript 复制代码
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#define filename "log.txt"
int main()
{
    fprintf(stdout,"hello normal message\n");
    fprintf(stdout,"hello normal message\n");
    fprintf(stdout,"hello normal message\n");
    fprintf(stdout,"hello normal message\n");
    fprintf(stderr,"hello error message\n");
    fprintf(stderr,"hello error message\n");
    fprintf(stderr,"hello error message\n");
    fprintf(stderr,"hello error message\n");
    return 0;
}

重 定 向 以 后,向 1 里 面 写 入 的 内 容 都 会 写 入 normal.txt 文 件 中。只 对 1 重 定 向,没 有 对 2 重 定 向。

1 可 以 省 略 不 写。stdout 和 stderr 可 以 重 定 向 到 1 个 文 件 中。

./mytest >err.txt 2>&1 先 表 示 把 1 号 文 件 描 述 符 的 内 容 写 入 err.txt 中,然 后 2>&1 表 示 把 2 号 文 件 描 述 符 中 的 内 容 写 入 1 号 文 件 描 述 符 中。


fprintf

将 字 符 写 入 文 件 或 使 用 流。

javascript 复制代码
#include<stdio.h>
#include<unistd.h>
#include<string.h>
int main()
{
    printf("pid:%d\n",getpid());
    //打开文件的路径和文件名,默认在当前路径下创建一个文件
    FILE* pf = fopen("test.txt","a");
    if(pf == NULL)
    {
        perror("fopen fail");
        return 1;
    }
    const char* str = "hello linux";
    fprintf(stdout,"%s,%d\n",str,1234);
    fclose(pf);
    return 0;
}

4、基 础 知 识

文 件 其 实 是 在 磁 盘 上 的,磁 盘 是 外 部 设 备,访 问 文 件 其 实 是 访 问 硬 件。操 作 系 统 是 硬 件 的 管 理 者。几 乎 所 有 的 库 只 要 是 访 问 硬 件 设 备,必 定 要 封 装 系 统 调 用。


(1)open

打 开 或 者 创 建 文 件 或 者 设 备,可 以 指 定 文 件 的 权 限,即 文 件 是 否 存 在。

flags

javascript 复制代码
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{    
    umask(0); // 文件掩码
    int fd = open("log.txt",O_WRONLY|O_CREAT,0666);
    if(fd<0)
    {
        printf("open fail\n");
        return 1;
    }
    return 0;
}



(2)close

关 闭 文 件

文 件 描 述 符
file descriptor :文 件 描 述 符,是 int 类 型。

javascript 复制代码
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{    
    umask(0); // 文件掩码
    int fd = open("log.txt",O_WRONLY|O_CREAT,0666);
    if(fd<0)
    {
        printf("open fail\n");
        return 1;
    }
    close(fd);
    return 0;
}

(3)write

向 文 件 中 写 入 文 件 描 述 符,返 回 值 是 实 际 写 入 的 字 节 数。默 认 从 文 件 的 开 始 处 写,不 会 对 文 件 清 空,让 新 增 加 的 字 符 替 换 掉 旧 的 字 符。

javascript 复制代码
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{    
    umask(0); // 文件掩码
    int fd = open("log.txt",O_WRONLY|O_CREAT,0666);
    if(fd<0)
    {
        printf("open fail\n");
        return 1;
    }
    const char* str = "hello world";
    write(fd,str,strlen(str));
    close(fd);
    return 0;
}

(4)标 志 位 传 递 方 式

1 个 整 数 可 以 传 递 1 个 标 志 位。

javascript 复制代码
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#define ONE (1 << 0)  //1
#define TWO (1 << 1)  //2
#define THREE (1 << 2)//4
#define FOUR (1 << 3) //8
void show(int flags)
{
    if(flags&ONE)
    {
        printf("hello function1\n");
    }
    if(flags&TWO)
    {
        printf("hello function2\n");
    }
    if(flags&THREE)
    {
        printf("hello function3\n");
    }
    if(flags&FOUR)
    {
        printf("hello function4\n");
    }
}
int main()
{    
    show(ONE);
    printf("-----------\n");
    show(ONE|TWO);
    printf("-----------\n");
    show(ONE|TWO|THREE);
    printf("-----------\n");
    return 0;
}

二、访 问 文 件 的 本 质

1、struct file

操 作 系 统 内 描 述 一 个 被 打 开 文 件 的 信 息。

直 接 或 者 间 接 包 含 以 下 属 性:

  1. 被 打 开 的 文 件 在 哪 个 位 置
  2. 基 本 属 性、权 限、大 小、读 写 位 置、谁 打 开 的。
  3. 文 件 的 内 核 缓 冲 区 信 息
  4. struct file *next 指 针。

对 文 件 的 操 作 改 为 对 双 向 链 表 的 增 删 查 改。

一 个 进 程 可 以 打 开 多 个 文 件,要 建 立 进 程 PCB 和 打 开 文 件 的 关 系。





2、FILE

C 语 言 中 的 FILE 是 C 库 中 自 己 封 装 的 结 构 体,里 面 包 含 文 件 描 述 符。

javascript 复制代码
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{   
    printf("stdin->fd:%d\n",stdin->_fileno);
    printf("stdout->fd:%d\n",stdout->_fileno);
    printf("stderr->fd:%d\n",stderr->_fileno);
    return 0;
}

3、close(1)

printf

可 以 使 用 close(1); 关 闭 显 示 器 使 printf 无 法 显 示 在 显 示 屏 上。说 明 printf 的 底 层 使 用 了 1 号 文 件 描 述 符。

javascript 复制代码
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{  
    close(1);
    printf("stdin->fd:%d\n",stdin->_fileno);
    printf("stdout->fd:%d\n",stdout->_fileno);
    printf("stderr->fd:%d\n",stderr->_fileno);
    return 0;
}


fprintf

javascript 复制代码
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{  
    close(1);
    int ret = printf("stdin->fd:%d\n",stdin->_fileno);
    printf("stdout->fd:%d\n",stdout->_fileno);
    printf("stderr->fd:%d\n",stderr->_fileno);
    fprintf(stderr,"printf ret:%d\n",ret);
    return 0;
}

如 果 关 闭 了 1 号 文 件 描 述 符,使 用 2 号 文 件 描 述 符 也 可 以 在 显 示 器 上 输 出。


4、fd

javascript 复制代码
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{    
    umask(0); // 文件掩码
    int fd1 = open("log.txt",O_WRONLY|O_CREAT,0666);
    int fd2 = open("log.txt",O_WRONLY|O_CREAT,0666);
    int fd3 = open("log.txt",O_WRONLY|O_CREAT,0666);
    int fd4 = open("log.txt",O_WRONLY|O_CREAT,0666);
    printf("fd1:%d\n",fd1);
    printf("fd2:%d\n",fd2);
    printf("fd3:%d\n",fd3);
    printf("fd4:%d\n",fd4);
    close(fd1);
    close(fd2);
    close(fd3);
    close(fd4);
    return 0;
}

返 回 的 整 数 值 都 是 数 组 的 下 标 且 都 是 整 数,返 回 的 整 数 值 都 是 从 3 开 始 的。0 是 stdin(键 盘 文 件),1 是 stdout(显 示 器 文 件),2 是 stderr(显 示 器 文 件)。


验 证

javascript 复制代码
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{   
    const char* str = "hello linux";
    write(1,str,strlen(str));
    write(2,str,strlen(str));
    return 0;
}

5、read

从 文 件 描 述 符 中 读 取。

javascript 复制代码
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{   
    char buf[100];
    ssize_t count = read(0,buf,sizeof(buf));
    if(count < 0)
    {
        return 1;
    }
    buf[count] = '\0';
    printf("%s\n",buf);
    return 0;
}

6、引 用 计 数 与 关 闭 文 件

引 用 计 数

关 闭 文 件 时,使 用 close 时,对 1 号 描 述 符 的 引 用 计 数 减 1,然 后 将 1 号 指 针 位 置 置 空 即 可,然 后 判 断 引 用 计 数 是 否 为 0,如 果 为 0,则 说 明 没 有 文 件 被 使 用,系 统 会 回 收 struct 对 象。如 果 不 为 0,则 说 明 还 有 文 件 被 使 用。


三、重 定 向

1、文 件 描 述 符 的 分 配 规 则

(1)原 版 代 码

javascript 复制代码
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#define filename "log.txt"
int main()
{  
    int fd = open(filename,O_CREAT|O_WRONLY|O_TRUNC,0666);
    if(fd < 0)
    {
        perror("open fail");
        return 1;
    }
    printf("fd:%d\n",fd);
    const char* str = "hello world\n";
    int cnt = 5;
    while(cnt)
    {
        write(fd,str,strlen(str));
        cnt--;
    }
    close(fd);
    return 0;
}

此 时 文 件 描 述 符 为 3,log.txt 所 对 应 的 文 件 权 限 为 664。


(2)close(0)

在 代 码 最 前 面 添 加 close(0),输 出 的 文 件 描 述 符 为 0。


(3)close(1)

在 代 码 最 前 面 添 加 close(1)

因 为 printf 的 底 层 使 用 了 stdout,stdout 的 文 件 描 述 符 为 1,这 里 将 1 关 闭,无 法 在 显 示 器 上 输 出。


(4)close(2)

在 代 码 最 前 面 添 加 close(2)

关 闭 2 号 文 件 描 述 符 后,输 出 的 文 件 描 述 符 为 2。

(5)总 结

关 闭 几 号 文 件 描 述 符,文 件 描 述 符 就 输 出 几 号,说 明 文 件 描 述 符 对 应 的 分 配 规 则 是 从 0 下 标 开 始,寻 找 最 小 的 没 有 使 用 的 数 组 位 置,它 的 下 标 就 是 新 文 件 的 文 件 描 述 符。

2、重 定 向 的 原 理

javascript 复制代码
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#define filename "log.txt"
int main()
{  
    close(1);
    int fd = open(filename,O_CREAT|O_WRONLY|O_TRUNC,0666);
    if(fd < 0)
    {
        perror("open fail");
        return 1;
    }
    const char* str = "hello world\n";
    int cnt = 5;
    while(cnt)
    {
        write(1,str,strlen(str));
        cnt--;
    }
    close(fd);
    return 0;
}

关 闭 1 号 文 件 描 述 符 后,结 果 没 有 在 显 示 器 中 显 示,却 写 入 了 文 件 中。

关 闭 1 号 文 件 描 述 符 后,此 时 打 开 文 件,文 件 原 来 应 该 指 向 3 号 文 件 描 述 符,现 在 被 改 成 了 1 号 文 件 描 述 符,此 时 发 生 了 输 入 重 定 向。

重 定 向 的 本 质 是 对 数 组 下 标 的 内 容 进 行 了 修 改。如 果 想 要 发 生 重 定 向 需 要 将 原 来 文 件 描 述 符 中 的 内 容 关 闭 或 者 覆 盖 掉 即可。


3、dup2

拷 贝 文 件 描 述 符 的 指 针 内 容,将 新 的 文 件 描 述 符 的 内 容 拷 贝 给 旧 的 文 件 描 述 符,然 后 关 闭 新 的 文 件 描 述 符。

4、输 入 重 定 向

javascript 复制代码
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#define filename "log.txt"
int main()
{  
    int fd = open(filename,O_CREAT|O_WRONLY|O_TRUNC,0666);
    if(fd < 0)
    {
        perror("open fail");
        return 1;
    }
    //重定向
    dup2(fd,1);
    close(fd);
    const char* str = "hello world\n";
    int cnt = 5;
    while(cnt)
    {
        write(1,str,strlen(str));
        cnt--;
    }
    close(fd);
    return 0;
}

原 来 1 号 文 件 描 述 符 可 以 将 内 容 输 出 到 显 示 器 中,重 定 向 以 后 显 示 器 无 法 输 出 内 容,输 出 的 是 文 件 的 内 容。


5、追 加 重 定 向

将 write 中 的 O_TRUNC 改 成 O_APPEND 即 可 实 现 追 加 重 定 向。

javascript 复制代码
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#define filename "log.txt"
int main()
{  
    int fd = open(filename,O_CREAT|O_WRONLY|O_APPEND,0666);
    if(fd < 0)
    {
        perror("open fail");
        return 1;
    }
    //重定向
    dup2(fd,1);
    close(fd);
    const char* str = "hello world\n";
    int cnt = 5;
    while(cnt)
    {
        write(1,str,strlen(str));
        cnt--;
    }
    close(fd);
    return 0;
}

6、输 入 重 定 向

javascript 复制代码
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#define filename "log.txt"
int main()
{
    int fd = open(filename,O_RDONLY);
    if(fd < 0)
    {
        perror("open");
        return 1;
    }
    dup2(fd,0);//从标准输入读取改为从文件中读取
    char buf[1024];
    ssize_t s = read(0,buf,sizeof(buf)-1);
    if(s>0)
    {
        buf[s]='\0';
        printf("echo:%s\n",buf);
    }
    return 0;
}

cat 的 输 入 重 定 向

从 文 件 中 读 取 改 为 从 键 盘 中 读 取。


7、printf 与 fprintf

printf 和 fprintf 用 的 都 是 stdin,可 以 修 改 文 件 描 述 符,改 变 输 出 的 位 置。

javascript 复制代码
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#define filename "log.txt"
int main()
{  
    int fd = open(filename,O_CREAT|O_WRONLY|O_APPEND,0666);
    if(fd < 0)
    {
        perror("open fail");
        return 1;
    }
    //重定向
    dup2(fd,1);
    printf("fd:%d\n",fd);
    printf("hello printf\n");
    fprintf(stdout,"hello fprintf\n");
    close(fd);
    return 0;
}

如 何 理 解 "linux 中 一 切 皆 文 件"

所 有 操 作 计 算 机 的 动 作 都 是 以 进 程 的 形 式 操 作 的,所 有 访 问 文 件 的 操 作 都 是 用 进 程 的 方 式 访 问 文 件 的。



四、总 结

本 文 已 帮 你 掌 握 Linux 文 件 操 作 核 心:文 件 定 义、文 件 描 述 符、重 定 向 本 质,及 C 库 与 系 统 调 用 的 关 系,也 理 解 了 "一 切 皆 文 件" 的 设 计。这 些 知 识 是 后 续 进 程 通 信、网 络 编 程 的 基 础。建 议 动 手 修 改 代 码 加 深 理 解,关 注 专 栏 Linux 探 索 之 旅:从 命 令 行 到 系 统 内 核,后 续 将 解 锁 更 多 进 阶 内 容,帮 你 搭 建 系 统 编 程 知 识 体 系。

相关推荐
MC丶科6 分钟前
【SpringBoot常见报错与解决方案】端口被占用?Spring Boot 修改端口号的 3 种方法,第 3 种 90% 的人不知道!
java·linux·spring boot
江公望21 分钟前
ubuntu kylin(优麒麟)和标准ubuntu的区别浅谈
linux·服务器·ubuntu·kylin
Lynnxiaowen22 分钟前
今天我们开始学习python语句和模块
linux·运维·开发语言·python·学习
生态笔记1 小时前
PPT宏代码
linux·服务器·powerpoint
mucheni1 小时前
迅为RK3588开发板Ubuntu 系统开发ubuntu终端密码登录
linux·运维·ubuntu
skywoodsky1 小时前
Ubuntu 24.04环境下的挂起转休眠
linux
小云数据库服务专线1 小时前
GaussDB 应用侧报Read timed out解决方法
linux·服务器·gaussdb
资源补给站1 小时前
服务器高效操作指南:Python 环境退出与 Linux 终端快捷键全解析
linux·服务器·python
一苓二肆1 小时前
代码加密技术
linux·windows·python·spring·eclipse
玉树临风江流儿1 小时前
Linux驱动开发实战指南-上
linux·驱动开发