个人Linux操作系统学习笔记11 - 环境变量

目录

main函数可以有参数吗?

(这个问题从Java中已知,有的)

c 复制代码
#include <stdio.h>
int main(int argc, char *argv[]) //因为c没有类似STL的功能,因此要用argc变量进行个数传参
{
  return 0;
}

发现可以正常编译与运行

c 复制代码
#include <stdio.h>
int main(int argc, char *argv[])
{
  printf("argc: %d\n", argc);
  int i = 0;
  for(; i < argc; i++)
  {
    printf("argv[%d]->%s\n", i, argv[i]);
  }
  return 0;
}

argc为参数个数,argv[]是一个char*类型字符串数组

运行结果如下:

bash 复制代码
$ ./code 
argc: 1
argv[0]->./code

$ ./code a
argc: 2
argv[0]->./code
argv[1]->a

$ ./code a b 3
argc: 4
argv[0]->./code
argv[1]->a
argv[2]->b
argv[3]->3

我们在命令行输入的本质就是字符串

shell程序获取之后,会根据空格拆分出多个字符串,作为参数传入

上面的./code a b 3拆为./codeab3总共4个字符串

看不到这个现象,因为是bash和系统自动完成的


传参的作用

c 复制代码
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
  if(argc != 2)
  {
    printf("参数数量错误!使用格式:%s -a|-b\n", argv[0]);
    return 1;
  }
  if(strcmp(argv[1], "-a") == 0)
  {
    printf("func1\n");
  }
  else if(strcmp(argv[1], "-b") == 0)
  {
    printf("func2\n");
  }
  else
  {
    printf("defalut func\n");
  }
  return 0;
}

可参考ls -a等命令

编译后运行

bash 复制代码
$ ./code 
参数数量错误!使用格式:./code -a|-b
$ ./code -a
func1
$ ./code -b
func2
$ ./code a
defalut func

细节:

  1. 命令行参数至少为1,argc >= 1,argv0一定有元素,指向的就是程序名

  2. 选项是以空格分隔的字符串,一个字符/数字,也是字符串

  3. argv\[\]的本质是一张"表",有argc的元素,argv[argc]内容一定为NULL(最后一个元素永远为NULL)

因此可以这样写for循环

c 复制代码
for(; argv[i]; i++)
{
  printf("argv[%d]->%s\n", i, argv[i]);
}

有一个现象:

bash 复制代码
$ ./mycommand 
this is a command
$ mycommand
-bash: mycommand: command not found

执行自己的程序时必须使用./调用

  1. ./相对路径,让OS找到用户要执行的bin(可执行程序)就在当前路径下

  2. Linux系统有类似环境变量的东西,PATH,系统会默认在这里查找程序

  3. PATH变量是shell语法自带的

bash 复制代码
$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/s......k/.local/bin:/home/s......k/bin
复制代码
    (其中`:`为分隔符)

    PATH的本质就是一个帮助Linux系统找到程序的变量 (windows同理)
  1. 如果想要将自己的程序可以不使用./调用:

  2. 添加到/usr/bin路径,不推荐:会污染环境变量

  3. 将自己的程序的路径添加到PATH

  4. 修改PATH:

bash 复制代码
$ PATH=/home/s......k/code/2025_10_16/
$ echo $PATH
/home/s......k/code/2025_10_16/
$ ls
-bash: ls: command not found

不能直接覆盖PATH!会导致系统无法正常查找其它指令

(退出账号重新登录即可恢复PATH为初始状态)

正确写法:

bash 复制代码
$ PATH=$PATH:/home/s......k/code/

这样就能正确添加路径

添加路径后,在系统中全局有效!(类似ls等命令)

  1. Windows系统也有(很熟悉,笔记就不写了)

环境变量:系统级的变量,变量名和变量内容,往往具有全局属性

使用env命令查看所有的环境变量

bash 复制代码
$ env
XDG_SESSION_ID=3......1
HOSTNAME=...... # 主机名
TERM=xterm # 终端类型
SHELL=/bin/bash # 当前系统用的shell程序
HISTSIZE=1000 # 记录最近历史命令的数量上限,使用 history 命令查看
SSH_CLIENT=0.0.0.0 3......9 22 # 当前云服务器登录用户的ip地址
SSH_TTY=/dev/pts/2 # 当前用户使用的终端文件
USER=s......k # 用户名 whoami
LD_LIBRARY_PATH=:/home/s......k/.VimForCpp/......
LS_COLORS=......
MAIL=......
PATH=/......bin
PWD=/home/s......k/code/ # 当前路径 pwd
LANG=en_US.UTF-8 # 编码格式
HISTCONTROL=ignoredups
SHLVL=1
HOME=/home/s......k # 家目录
LOGNAME=s......k # 登录用户名
CVS_RSH=ssh
SSH_CONNECTION=0.0.0.0 3......9 0.0.0.0 22
LESSOPEN=||/usr/bin/l.......sh %s
XDG_RUNTIME_DIR=/run/user/1004
_=/usr/bin/env
OLDPWD=/home/s......k/ # 上一次所在的路径,使用 cd - 命令

了解PTAH,HOME,SHELL是什么就行


环境变量与C/C++代码之间的联系

c 复制代码
#include <stdio.h>
int main(int argc, char* argv[], char* env[])//env就是环境变量
{
  int i = 0;
  for(; env[i]; ++i)
  {
    printf("env[%d]: %s\n", i, env[i]);
  }
  printf("this is a command\n");
  return 0;
}
bash 复制代码
$ ./mycommand 
env[0]: XDG_SESSION_ID=3......1
# ......
env[23]: OLDPWD=/home/s......k
this is a command

env[]就是系统的环境变量表


语言中有一个char** environ 一直指向环境变量表

这是获取环境变量的第二种方法

c 复制代码
#include <stdio.h>
#include <unistd.h>
int main()
{
  extern char** environ;
  int i = 0;
  for(; environ[i]; ++i)
  {
    printf("environ[%d]->%s\n", i, environ[i]);
  }
  return 0;
}

上面的两种方法都不常用!

getenv可以直接根据变量名获取变量值,否则为NULL

c 复制代码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
  char* whoami = getenv("USER");
  if(whoami == NULL)
  {
    printf("no USER!\n");
    return 0;
  }
  else if(strcmp(whoami, "root") == 0)
  {
    printf("can NOT use root!\n");
  }
  else
  {
    printf("you are %s\n", whoami);
  }
  return 0;
}

这样可以写出一个root用户无法使用的程序


环境变量表存储在bash之中,而bash在内存中,因此重新打开云服务器终端即可恢复环境变量表为初始状态。

因此修改环境变量是内存级的

因为所有用户执行的程序与命令,都是bash的子进程,而子进程是可以访问父进程的数据,因此子进程可以访问到bash修改后的全局变量

c 复制代码
#include <stdio.h>
#include <unistd.h>
char* argv[100];
char* env[100];
int main()
{
  argv[0] = (char*)"ls";
  argv[1] = (char*)"-a";
  env[0] = (char*)"PATH=AAAA";
  pid_t id = fork();
  if(id == 0)
  {
    int i = 0;
    for(; argv[i]; ++i)
      printf("%s\n", argv[i]);
    for(i = 0; env[i]; ++i)
      printf("%s\n", env[i]);
  }
  else
    sleep(10000);
}

可以正常打印,说明子进程可以获取父进程的环境变量

我们平时执行的程序,都是bash的子进程,因此这些程序的环境变量都是bash提供

总结:环境变量由父进程提供

因此所有进程都会识别到bash的环境变量


bash的环境变量从何而来?

从Linux系统的配置文件中获取

平时手动在命令行修改的环境变量只改了bash,不会修改配置文件,因此重启bash即可重新获取系统配置文件的环境变量表

从哪个配置文件中获取?

bash 复制代码
$ cd ~
$ ls -al # 要在家目录中查看
total 100
-rw-r--r--   1   193 Oct 31  2018 .bash_profile
-rw-r--r--   1   355 Nov 27 21:01 .bashrc
shell 复制代码
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi

# User specific environment and startup programs

PATH=$PATH:$HOME/.local/bin:$HOME/bin

export PATH
shell 复制代码
# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
    . /etc/bashrc
fi

# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=

# User specific aliases and functions
alias vim='/home/s......k/.VimForCpp/nvim'
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:~/.VimForCpp/......
shell 复制代码
# /etc/bashrc

# System wide functions and aliases
# Environment stuff goes in /etc/profile

# It's NOT a good idea to change this file unless you know what you
# are doing. It's much better to create a custom.sh shell script in
# /etc/profile.d/ to make custom changes to your environment, as this
# will prevent the need for merging in future updates.

# are we an interactive shell?
if [ "$PS1" ]; then
 ......
# vim:......

在启动bash时,先调用.bash_profile,然后调用.bashrc,然后调用/etc/bashrc

修改文件:

shell 复制代码
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi

# User specific environment and startup programs

PATH=$PATH:$HOME/.local/bin:$HOME/bin

export PATH

echo "This is a change in .bash_profile!"

重新启动bash:

bash 复制代码
Welcome to ...... Cloud Elastic Compute Service !

This is a change in .bash_profile!

因为每个用户都有自己的家目录,因此只会修改当前用户的bash


本地变量

bash 复制代码
$ TEST_ENV=12345
$ env | grep TEST_ENV
$ echo $TEST_ENV
12345

这种在shell中定义的是本地变量,不会保存在环境变量表中

使用export导出至环境变量表

bash 复制代码
$ export TEST_ENV
$ env
# ...
TEST_ENV=12345
# ...

此时 TEST_ENV 也可以被程序获取

使用unset删除环境变量

bash 复制代码
$ unset TEST_ENV
$ env
# 没有 TEST_ENV

以上操作都是内存级

本地变量:

  • 本地变量无法被子进程继承,不具备全局性,只在bash内部可以访问

  • 使用export写入变量表,变为全局变量

  • 本地变量有自己的语法

bash 复制代码
$ cnt=0; while [ $cnt -le 10 ]; do echo $cnt; let cnt++; done
0
1
2
3
4
5
6
7
8
9
10

使用env查看环境变量,使用set查看环境变量和本地变量


如果需要将环境变量写为永久,就写到 ~/.bash_profile


bash 复制代码
$ local_value=100
$ env | grep local_value
$ echo $local_value
100

local_value是本地变量,为什么echo可以获取到该变量?

bash 复制代码
$ PATH=''
$ echo $PATH

$ ls
-bash: ls: No such file or directory
$ pwd
/home/....../code/
$ top
-bash: top: No such file or directory
$ echo "aa"
aa

明明PATH为空,但是一部分程序能运行,一部分不能运行?

命令与命令之间是不一样的

  • 存在的二进制级别的命令:普通命令

  • 内建命令:在shell内部自己定义,bash内部的一次函数调用,不依赖第三方路径

    相当于编程语言中语言自带的函数(暂时这样理解!)

相关推荐
Kina_C1 小时前
NFS与Autofs快速讲解-从原理到实战配置
linux·nfs·autofs
皮卡狮1 小时前
文件系统:磁盘硬件寻址和系统软件寻址
linux
是潮汕的灿灿展吖2 小时前
Centos离线部署nfs操作
linux·运维·centos
Kina_C2 小时前
Apache HTTP Server 安装、配置与高级功能详解
linux·http·apache
治愈系贝壳2 小时前
ARM --- day 6 时钟
linux·arm开发·学习
依然范特东2 小时前
强化学习笔记2--bellman equation
人工智能·笔记
minglie13 小时前
zynq高频小数据量PS闭环的三个实验-第0课:目的和目标
学习
Molesidy3 小时前
【GUI】【AWTK】基于开阳平台的GUI界面设计环境搭建
linux·gui·awtk
乐观勇敢坚强的老彭3 小时前
信奥C++一维数组笔记
开发语言·c++·笔记