System、环境变量和set指令

一、System

  1. system()函数是C++标准库中的一个函数,它允许程序执行系统命令。该函数定义在头文件中。
  2. 返回 0 表示命令执行成功,-1 表示系统错误
  3. 该函数谨慎使用,不要让用户的输入传递给该函数
  4. system() 会创建新的进程来执行命令,比较占用资源
  5. 对于跨平台代码,需要注意兼容性,可以使用预编译写 几套
#ifdef _WIN32
        system("mkdir new_folder");
    #else
        system("mkdir -p new_folder");
    #endif
 // Linux系统示例
    system("ls");   // 列出当前目录文件
    system("clear"); // 清屏
   // 检查命令执行结果
    int result = system("somecommand");
    if (result == 0) {
        std::cout << "命令执行成功" << std::endl;
    } else {
        std::cout << "命令执行失败" << std::endl;
    }

二、exec族函数

  1. exec族函数是一组用于执行新程序的函数,它们会用新的进程映像替换当前进程的映像
  2. 相当于是替换了该进程,借壳(pid)上市
  3. 经常和fork函数一同使用

1.替换原理

  1. 当前进程的内存被清空:调用exec时,当前进程的地址空间(包括代码、数据和堆栈)将被完全清除。
  2. 加载新程序:新程序(指定的可执行文件)会被加载到进程的内存中,覆盖原来的进程内容。
  3. 新的程序开始执行:加载完新程序后,进程从新程序的入口点(main()函数对应上述的入口地址)开始执行。
  4. 进程ID保持不变:虽然进程的内存和执行代码被替换,但进程的ID(PID)仍然是原进程的PID,进程的资源(如打开的文件缓冲区)默认不会改变,除非显式地进行操作。
  5. 注意的是之前进程所拥有的资源并不会被释放

2. 注意点

  • exec函数执行成功后永远不会返回,因为当前进程已被新进程替换
  • 只有执行失败时才会返回-1,并设置errno
  • 如果参数固定,使用execl/execlp
  • 如果参数动态构建,使用execv/execvp

3. 相关函数和使用示例

#include <unistd.h>

int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
  1. execl
int main() {
    // execl需要提供完整路径+可执行程序,参数以列表形式传递,最后必须以NULL结尾
    execl("/bin/ls", "ls", "-l", "-a", NULL);
    // 如果执行失败才会运行到这里
	
	//第二个参数通常是执行的程序的名称,并且会传递给执行程序的argv[0]参数。
	//第二个参数必须有值,在不使用argv[0]的时候,可以是任意字符串
    execl("./example.txt","example",NULL);
    std::cerr << "execl failed!" << std::endl;
    return 1;
}

  1. excelp
  • 使用excelp可以不需要关心程序的具体路径
  • execlp特别有用的场景是当你知道你要执行的程序的名称,但不确定它的路径时。由于execlp会自动查找PATH,它使代码更加简洁和灵活,避免了手动指定路径。
  • 只不过依赖PATH罢了。
    execlp("ls", "ls", "-la", NULL);
    
  1. execle
  • 定制子程序的环境变量
int execle(const char *path, const char *arg, ..., char * const envp[]);
int main() {
    // 设置新的环境变量
    char * const envp[] = {"PATH=/bin", "MY_VAR=HelloWorld", NULL};

    // 使用 execle 执行 ls 命令,并指定新的环境变量
    execle("/bin/ls", "ls", "-l", NULL, envp);

    // 如果 execle 执行失败,会执行下面的代码
    std::cerr << "execle failed!" << std::endl;
    return 1;
}

  1. execv
  • 将excel的参数装进了数组
  • 允许通过参数数组来传递命令行参数
int execv(const char *path, char *const argv[]);
int main() {
    // 设置参数数组
    char *args[] = {"ls", "-l", NULL};

    // 使用 execv 执行 ls 命令,传递参数数组
    execv("/bin/ls", args);

    // 如果 execv 执行失败,执行下面的代码
    std::cerr << "execv failed!" << std::endl;
    return 1;
}
  1. execvp
  • 类似execvp
int main() {
    // 设置参数数组
    char *args[] = {"ls", "-l", NULL};

    // 使用 execvp 执行 ls 命令,执行时会根据 PATH 查找 ls
    execvp("ls", args);

    // 如果 execvp 执行失败,执行下面的代码
    std::cerr << "execvp failed!" << std::endl;
    return 1;
}
  1. execvpe
    类似execle
// 设置参数数组
    char *args[] = {"ls", "-l", NULL};

    // 设置自定义环境变量
    char *env[] = {"MY_VAR=HelloWorld", "PATH=/bin", NULL};

    // 使用 execvpe 执行 ls 命令,并指定新的环境变量
    execvpe("ls", args, env);

三、环境变量

  1. 在 Linux 系统中,环境变量(Environment Variables)是存储系统或用户配置的键值对,它们控制程序的行为或定义系统的特定设置。
  2. 环境变量通常用于存储系统路径、语言设置、终端配置等重要信息,影响程序的执行、外部命令的查找、文件路径的解析等。
  3. 它们的作用范围可以是全局的,也可以是针对特定用户或进程的。

1.环境变量分类

1.1系统环境变量
  • 这些环境变量对所有用户和进程有效,通常由系统管理员或系统启动脚本设置。
  • 有三个文件可以编辑,这三个文件中的配置都会影响系统范围内的所有用户,属于系统级的配置机制,但是它们的作用方式和适用场景有所不同
1.1.1/etc/environment
  • 完全静态,只定义变量,没有脚本逻辑,因此可以直接归类为系统环境变量。
  • 生效范围广,适用于所有用户和进程。
  • PATH 的顺序很重要,系统会按照从左到右的顺序查找可执行文件,因此如果同名命令在多个目录中存在,优先使用最左边的目录中的版本
这是我的环境变量
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin"
添加的方式有两种
	1.在PATH的字符串里面加<<:路径>>
	2.或者另起一行,一般这样做,看得出来被修改
		PATH="$PATH:/your/new/directory"
		//其中$PATH是为了确保你保留现有的 PATH 值,并在其后追加新的目录,不加就完蛋了
	3.保存重启即可生效,或者执行以下命令
		source /etc/environment
当然可以自定义添加一些环境变量,不过不推荐,这是系统级,少一点还是好。
	格式为:MY_APP_HOME="/opt/myapp"

1.1.2/etc/profile
  • 在用户登录时运行,用于配置登录 shell 的全局环境变量。
    全局作用:对所有用户的登录 shell 生效。
    支持脚本:允许使用复杂的 shell 脚本(如条件语句、函数等)。
    适用场景:通常用于设置需要动态计算的环境变量或初始化脚本。
  • 仅对登录 shell 有效,非登录 shell(如子 shell)不加载
    • 并不是打开shell终端就是登录哈。
1.1.2.1登录和非登录的区别
特性登录 Shell非登录 Shell
启动方式用户登录系统(ssh、终端登录或 bash --login打开终端仿真器或直接运行 bash
加载文件/etc/profile~/.bash_profile 等全局配置文件仅加载 ~/.bashrc(交互配置文件)。
使用场景初始化用户环境,例如环境变量、语言、路径等用于交互操作或运行脚本。
继承父进程变量不完全继承,重新初始化环境变量完全继承父 Shell 的环境变量。
是否交互式可以是交互式或非交互式通常是交互式,但也可用于脚本执行。
  • 系统级的环境变量和启动程序
1. 定义全局环境变量
	export JAVA_HOME=/usr/lib/jvm/java-11-openjdk
	export PATH=$JAVA_HOME/bin:$PATH
	所有用户登录时,都会加载这些变量。
	不加export只会生效于当前shell
	注意可能与environment冲突
		故export PATH=/custom/path:$PATH  # 添加到开头
		# 或
		export PATH=$PATH:/custom/path  # 添加到末尾
2.加载其他配置条件
	在/etc/profile.d/目录下 注意权限问题
	以.sh 结尾的文件,注意谨慎使用和创建

2. 设置系统级别的别名
	alias ll='ls -l'
	alias df='df -h'
3. 定义全局函数
	show_mem() {
    free -h
	}
4. 设置默认权限掩码
	umask 022  # 设置新建文件的默认权限
5. 配置系统提示符
	export PS1="\u@\h:\w\$ "
6.系统启动时的招呼语
	echo "Welcome to the system!"
6. 设置历史记录相关配置
	export HISTSIZE=1000
	export HISTFILESIZE=2000
	export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "
1.1.3/etc/bash.bashrc
  • /etc/bash.bashrc 是 Bash shell 的全局配置文件
  • 在 Bash Shell 会话中加载,尤其影响非登录 shell。也就是每次打开的终端
设置全局命令别名
	alias ll='ls -l'
	alias la='ls -la'
	alias grep='grep --color=auto'
设置历史记录
	# HISTSIZE: 设置当前 shell 会话中保存的最大历史命令条数
	# 超过此条数后,最早的记录会被丢弃,仅对内存中的历史有效
	HISTSIZE=1000
	
	# HISTFILESIZE: 设置 .bash_history 文件中保存的最大历史命令条数
	# 超过此条数后,最早的记录会被丢弃,仅对磁盘文件中的历史有效
	HISTFILESIZE=2000
	
	# HISTCONTROL: 控制命令历史记录的过滤规则
	# ignoredups: 忽略连续重复的命令
	# ignorespace: 忽略以空格开头的命令
	# ignoreboth: 同时忽略上述两类命令
	# erasedups: 删除历史中所有重复的命令,仅保留最后一次
	HISTCONTROL=ignoredups
	
	# HISTTIMEFORMAT: 设置显示命令历史时的时间戳格式
	# 格式说明:
	#   %Y: 年份
	#   %m: 月份
	#   %d: 日期
	#   %H: 小时(24小时制)
	#   %M: 分钟
	#   %S: 秒
	# 时间戳仅在使用 `history` 查看时显示,不会存储到 .bash_history 文件中
	HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "
	
	# 配置生效后,可通过 history 命令查看历史命令,效果如:
	#  1  2024-11-30 12:30:00 ls
	#  2  2024-11-30 12:31:10 pwd
启用补全功能
	if [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
	fi
定义全局函数


  • 历史记录
    在这里插入图片描述
    /etc/profile 的主要区别:
比较方面/etc/profile/etc/bash.bashrc
加载时机登录 shell 时加载(如 SSH 登录)每个新 bash shell 启动时都会加载
作用范围适用于所有 shell只适用于 bash shell
典型用途主要设置环境变量主要设置 shell 行为和交互特性
1.2用户级环境变量
  • 仅适用于特定用户,由该用户单独设置。
  • 存储在用户配置文件中,如 ~/.bashrc、~/.zshrc 或 ~/.profile。
  • 格式固定,不能添加 shell 命令或函数
1.2.1 ~/.bashrc
  1. ~/.bashrc 是 Bash Shell 用户的配置文件,通常用于设置非登录 Shell 的环境和行为。它会在 每次启动非登录交互式 Shell 时自动加载
  2. 位置:每个用户都有自己的 ~/.bashrc 文件,位于用户的主目录下。save是备份哈
    在这里插入图片描述
  3. 具体用法
定义环境变量。
	export PATH=$PATH:/custom/path
	export EDITOR=vim
	export LANG=en_US.UTF-8

配置命令别名。
	alias ll='ls -alF'
	alias la='ls -A'
	alias l='ls -CF'

自定义提示符(Prompt)。
	export PS1="\u@\h:\w\$ "
		\u:用户名。
		\h:主机名。
		\w:当前工作目录。
		\$:提示符字符(普通用户为 $,超级用户为 #)。

配置 Shell 行为(如历史记录、自动补全等)
启用shell功能
	shopt -s checkwinsize         # 自动调整终端大小
	shopt -s autocd               # 允许直接输入目录名称进行切换
	shopt -s cdspell              # 自动纠正拼写错误的目录名称
设置函数
	function mkcd() {//实现一个快捷命令 mkcd,同时创建目录并切换到该目录
    mkdir -p "$1" && cd "$1"
	}


  1. 加载时机
  • 打开终端仿真器(如 GNOME Terminal、Konsole)。
  • 运行非登录的交互式 Bash Shell
  • 被登录 Shell 显式调用(通过在 ~/.bash_profile 中引入 ~/.bashrc)
1.2.2~/.profile
  1. ~/.profile 是一个用户级的配置文件,用于定义登录 Shell 的环境设置。它主要在用户登录系统时被加载,并为用户会话设置默认的环境变量和系统行为。
    在这里插入图片描述
  2. 位置:位于用户的主目录下(~/.profile)
  3. 主要用法
设置全局环境变量(例如 PATH、LANG)。
配置用户的启动环境。
调用其他配置文件(如 ~/.bashrc)。
  1. 加载时机
    • 用户通过登录 Shell 登录系统
    • 作为其他配置文件的备用
      - 如果 ~/.bash_profile 或 ~/.bash_login 文件不存在,则 ~/.profile 会被登录 Shell 加载
    • 对于非登录 Shell(如直接打开终端仿真器),~/.profile 不会自动加载。
  2. 加载优先级,找到第一个即停止
    • ~/.bash_profile
    • ~/.bash_login
    • ~/.profile
1.2.3~/.bash_logout
  • ~/.bash_logout 是一个用户级配置文件,用于定义 用户退出登录 Shell 时执行的清理操作。它由 Bash Shell 自动调用,通常用于在用户退出会话时清理环境或执行一些收尾工作。
  • 有点像RALL,析构。
  • 位置:位于用户的主目录下(~/.bash_logout)
  • 用法
    清理用户会话环境。
    删除临时文件或关闭服务。
    提供退出时的自定义行为。
     示例
     # 删除临时文件
    rm -rf /tmp/*
    
    # 打印退出信息
    echo "Goodbye, $USER. Your session has ended."
    
    # 保存命令历史记录
    history -a
    
    # 关闭后台服务
    if pgrep my_custom_service > /dev/null; then
        killall my_custom_service
        echo "Stopped my_custom_service."
    fi
    
    
1.3会话级环境变量
  • 仅在当前会话(例如一个终端窗口)中有效,通常通过临时命令(如 export)设置。
  • 使用以下命令查看当前会话中的环境变量printenv或env
  • 特定变量值
echo $VAR_NAME 查看特定变量
unset VAR_NAME 使用 unset 删除会话中的变量


  • 在shell中对父子进程的使用
bash //进入子进程
exit //退出子进程

//使用 export
export SHARED_VAR="hello"
bash
echo $SHARED_VAR  # 子进程中可以访问 SHARED_VAR
//不使用 export
# 设置普通变量
TEST_VAR="hello"

# 启动子进程(新的shell)
bash
echo $TEST_VAR  # 输出为空,子进程无法访问

# 直接使用 set 定义变量	(默认情况下,使用 set 定义的变量是局部变量,不会被子进程继承。)
	set VAR_NAME=value

  • 用法
# 临时设置代理
export http_proxy="http://127.0.0.1:7890"
export https_proxy="http://127.0.0.1:7890"

# 临时修改语言环境
export LANG="en_US.UTF-8"

# 临时修改编辑器
export EDITOR="vim"
配置临时路径
	export PATH=$PATH:/temporary/path
设置调试参数(为程序运行临时设置调试环境变量)
	export DEBUG=true
临时禁用功能
	export HISTSIZE=0
直接使用 set 定义变量	(默认情况下,使用 set 定义的变量是局部变量,不会被子进程继承。)
	set VAR_NAME=value

1.4归纳
类别生效范围优先级生效时间典型用途
系统环境变量全局(所有用户)系统启动后长期生效配置系统关键参数(如路径)
用户级环境变量单用户用户登录后长期生效配置用户个性化参数
会话级环境变量当前终端或进程当前会话,关闭即失效临时调整变量(如调试模式)

2. 常见环境变量

环境变量描述
HOME当前用户的主目录路径
USER当前用户的用户名
LOGNAME当前登录用户的用户名
SHELL当前使用的 shell 类型(如 /bin/bash
PATH可执行文件的搜索路径
LANG系统的默认语言和区域设置
LANGUAGE可接受的语言顺序
LC_*各种区域设置(如 LC_TIMELC_NUMERICLC_CTYPE 等)
DISPLAY指定 X11 显示的显示设备(如 :0
TERM当前终端类型(如 xterm-256color
PWD当前工作目录
EDITOR默认的文本编辑器(如 vimnano
HISTSIZEBash shell 中保存的历史命令数量
SSH_AUTH_SOCKSSH 认证代理的 socket 路径
PS1提示符的格式化字符串
XDG_SESSION_TYPE当前会话类型(如 x11wayland
XDG_SESSION_ID当前会话的 ID
XDG_CONFIG_DIRS配置文件搜索路径,通常包含 /etc/xdg
XDG_RUNTIME_DIR当前会话的运行时目录
TERM_PROGRAM当前终端程序的类型(如 Apple_Terminalgnome-terminal
QT_IM_MODULEQt 使用的输入法模块
LC_CTYPE定义字符分类行为的区域设置(如字符编码)
LC_TIME时间和日期格式的区域设置
LC_NUMERIC数字格式的区域设置
LC_MONETARY货币格式的区域设置
LC_PAPER纸张大小的区域设置
LC_ADDRESS地址格式的区域设置
LD_LIBRARY_PATH动态库搜索路径
TMPDIR临时文件存储目录

四.set指令

  • 内置命令,用于配置和显示 Shell 的环境选项、变量和参数。它是一个功能非常强大的工具,可以控制 Shell 的行为、设置位置参数、显示环境变量等。

1.基本功能

  • set # 显示所有变量和函数
  • set -o # 查看所有 shell 选项设置
  • set +o # Shell 选项会以一种可以直接写入脚本的格式输出
    在这里插入图片描述
    • 设置
      • 开启:set -o xxx:启用选项
      • 关闭:set +o xxx:禁用选项
  • 选项功能
选项状态作用
allexportoff如果打开(on),所有定义的变量会自动通过 export 成为环境变量。
braceexpandon启用大括号扩展,例如 {a,b,c} 扩展为 a b c
emacson启用 Emacs 风格的命令行编辑模式,支持 Ctrl+ACtrl+E 等快捷键。
errexitoff如果打开(on),脚本中命令出错(返回非零状态)会导致脚本立即退出。
errtraceoff如果打开(on),允许在函数或子 shell 中捕获 ERR 信号(错误处理)。
functraceoff如果打开(on),允许函数继承 DEBUGRETURN trap(调试功能)。
hashallon启用命令路径的哈希缓存,加快命令查找速度。
histexpandon启用命令历史扩展功能,如使用 ! 调用历史命令(!!!123 等)。
historyon启用命令历史记录功能,可通过 history 查看和调用历史命令。
ignoreeofoff如果打开(on),禁止通过 Ctrl+D 退出 shell,必须使用 exit 命令。
interactive-commentson允许在交互式 shell 中使用 # 注释。
keywordoff如果打开(on),允许在 shell 脚本中直接使用 shell 关键字功能。
monitoron启用作业控制功能(支持后台运行、Ctrl+Z 暂停、fg 恢复等)。

2.常用选项

  1. set -x 和 set +x 是 Bash 的调试工具,用于控制调试模式的启用和关闭。这些命令非常有用,尤其是在开发和调试 Bash 脚本时,能帮助定位问题或跟踪脚本执行过程。
    • set -x:用调试模式
      • 显示命令执行过程:在调试模式下,Bash 会打印每条执行的命令及其参数。
      • 用于检查脚本的执行流程。
      • 帮助排查脚本中的逻辑错误或未预期的行为。
    • 举例
    #!/bin/bash
    # 显示行号
    set -n
    
    echo "Step 1: No debugging here"
    
    set -x
    echo "Step 2: Debugging starts"
    ls /etc/passwd
    echo "Step 3: Debugging ends"
    set +x
    
    echo "Step 4: Back to normal execution"
    
    执行结果
    Step 1: No debugging here
    + echo 'Step 2: Debugging starts'
    Step 2: Debugging starts
    + ls /etc/passwd
    /etc/passwd
    + echo 'Step 3: Debugging ends'
    Step 3: Debugging ends
    Step 4: Back to normal execution
    
  2. 如下
命令作用场景
set -x启用调试模式,显示执行的每条命令及其参数。调试脚本执行流程,帮助快速定位问题。
set +x关闭调试模式,恢复默认状态。调试完成后关闭,避免输出过多信息。
set -e遇到错误(命令返回非零状态)时立即退出脚本。防止脚本在错误状态下继续执行,避免产生更严重的后果。
set +e关闭立即退出功能。在容错性较高的脚本中,允许部分命令出错而不退出整个脚本。
set -u使用未定义变量时报错并退出脚本。强制检查变量是否定义,避免因拼写错误或缺少变量而导致的潜在问题。
set +u关闭未定义变量检查功能。脚本中可能存在合法的未定义变量或默认值,关闭检查以避免误报。
set -o noclobber防止重定向覆盖已有文件(如 >)。保护关键文件,避免因误操作覆盖重要数据。
set +o noclobber允许重定向覆盖文件(默认行为)。需要在脚本中覆盖文件时使用。
set -v显示脚本执行前的原始代码(逐行打印)。用于检查脚本逻辑或语法问题,配合 -x 使用效果更佳。
set +v关闭原始代码显示功能。执行完成后关闭,保持输出整洁。
set -o pipefail如果管道中的任意命令失败,则整个管道返回失败。确保管道中所有命令都成功执行,避免后续操作依赖错误的中间结果。
set +o pipefail关闭管道失败传播功能(默认行为)。允许管道中的某些命令失败而不影响整个脚本执行。
  1. 常见用法
# 脚本开头的安全设置
set -euo pipefail

# 等同于:
set -e  # 出错时退出
set -u  # 使用未定义变量时报错`在这里插入代码片`
set -o pipefail  # 管道中的错误也会导致退出

或者
	set -euxo pipefail  # 启用调试、错误检查、未定义变量检查和管道错误传播

3.特殊用法

格式:set -- [参数1] [参数2] [参数3] ...
	参数1、参数2...:依次设置为位置参数 $1、$2、$3 等
例如
	set -- hello world bash
	echo $1  # 输出 hello
	echo $2  # 输出 world
	echo $3  # 输出 bash


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值