起因

突然想用 GNU readline 重新实现一下 bash 自带的 read 或者只是实现最简单的功能,但至少不要像 read 那样输入中文在退格就出毛病吧

read 命令是什么呢,它是一个 bash 的内建功能,用来向用户读取键盘输入并直接写入一个环境变量或者变量数组。
此处的环境变量是指,在启动 Shell 中调用的任何程序都能使用的变量,这到后面会是一个大问题

setenv()

man7.org

setenv()unsetenv()GNU libc 实现中的一部分,编译器可能不会自动启用他们,
所以记得试试用 -std=gnu17 编译器标志快速打开所有非标准功能,或者用 -D_POSIX_C_SOURCE=200112L(手册里写的最低 POSIX C 版本限度)标志定义要使用的 POSIX 功能版本

所以,只需要像这样就行了吗?

setenv("envName", "envValue", true /* overwrite */);
puts(getenv("envName"));

其实此时的程序输出应该是正常的,但在执行后其他程序并不能访问这个变量。
这是因为至少 Linux 下的环境变量是为每个进程单独设置的。子进程可以访问父进程的变量,不能创建能给父进程使用的变量

Shell 本身是一个进程,Shell 里调用的任何一个程序也都是个新进程

这也是为什么 bash 中的 read 是个内建关键字,而不是各独立的二进制文件,还有 source 这种关键字专门用来加载别的脚本中的函数和变量。
这是篇写的挺好的解释:https://stackoverflow.com/a/3416693/25416550

至于我最开始的想法嘛,其实还有个原因。
如果不是用命令自己直接赋值而是使用 envName=$(read) 的话,程序的提示词和回显也会被送进去,问题也很多