%% # 纲要 > 主干纲要、Hint/线索/路标 # Q&A #### 已明确 #### 待明确 > 当下仍存有的疑惑 **❓<font color="#c0504d"> 有什么问题?</font>** # Buffer ## 闪念 > sudden idea ## 候选资料 > Read it later %% # "shell 变量" 与 "环境变量" 在 Linux 中有两种类型的变量: - **shell 变量**(也称 "**局部变量**"): - 定义:在**当前 shell 会话**中定义的变量 - 特点:**==仅在定义这一变量的 shell 示例中可见==**,**不会传递给子进程**。 - **环境变量**: - 定义:**通过 `export` 命令导出或定义的 shell 变量 - 特点: - 仅对 ==**定义该"环境变量的"shell 会话== 以及 =="定义后才启动的所有子进程== 可见; - 对 **==定义该"环境变量的"shell 会话的父进程== 以及 ==定义该环境变量之前已运行的子进程== 都不可见; - 在**子进程中"修改" 环境变量的值后,只对该子进程有效**,不影响其父进程中的环境变量值 > [!note] 子进程会 "继承/复制" 父进程的环境 > > - 在子进程创建时,**系统为子进程 "==复制==" 了父进程的环境**,<br>因此父进程的全部 「**环境变量**」,其子进程也可以访问。 > > > - 子进程中对 "**环境变量**" 的修改不会影响到父进程,而**只对==该子进程自身==有效**。 > ^ebucbz shell 本身提供了一些内置的系统环境变量,以及一些特殊变量。 - **系统环境变量**:例如 `PATH`、`USER`、`HOME`、`IFS`、`SHELL` 等。 - **特殊变量**:例如 `$?`,`$`, `$#`,`$@`,`$*` ,`$!` 等 > **系统环境变量**基本上会使用全大写字母,例如 `HOME`,以区别于用户自定义的环境变量。因此**用户自定义变量应当以小写命名**。 <br><br><br> # 定义变量 ### (1)定义 shell 变量 - 用户自定义变量的名称可以是任何由**字母、数字或下划线**组成的字符串,长度不超过 20 个字符 - 使用等号 `=` 为变量赋值,**变量、等号、值之间不能有空格**。 - shell 脚本**以字符串形式**存储所有的变量值 - shell 脚本中定义的变量的生命周期为**整个脚本执行期间**,**脚本结束时被删除**。 ```shell var1=10 var2=-57 var3=testing var4="still more testing" ``` #### 空变量 shell 中定义一个**空变量**通过**直接赋值一个空字符串**来实现,可以使用**空的双引号 `""` 或单引号 `''`**。 > [!NOTE] 检查变量是否为空 > > - `-n` 验证变量值**不为空**,不为空时返回 true > - `-z` 验证变量值**为空**,为空时返回 true 示例: ```shell str1=Soccer str2='' if [ -n "$str1" ]; then echo "The string $str1 is NOT empty" else echo "The string $str1 IS empty" fi if [-z "$str2"]; then echo "The string $str2 IS empty" else echo "The string $str2 is NOT empty" fi ``` #### 数组变量 shell 变量可以作为「**数组**」使用,即 "**存储了多个值的变量**",这些值即可以单独引用,也可以作为整体引用。 - **定义数组变量**:值放在圆括号中,值与值之间以空格分隔 - **引用单个数组元素值**:必须使用 `${var[idx]}` 形式。 ```shell my_var=(zero one two three four) echo $mytest # 引用整体 echo ${mytest[0]} # 引用单个数组元素值 echo ${mytest[2]} ``` #### 只读变量 通过 `readonly` 或 `declare -r` 命令**在当前 shell 中**创建只读变量,**其值在创建之后就不能再更改**。 一旦变量被标记为只读,**任何试图修改它的值的操作都会导致错误**。 ```sh readonly MYVAR="value" # 或者 declare -r MYVAR="value" ``` 在 Bash 中,有些变量(如 `$BASH_VERSION`、`$SECONDS`)和特殊的 Shell 参数(如 `$RANDOM`、`$LINENO`)天然就是只读的,不能被用户修改。 ### (2)定义环境变量 创建环境变量:通过 `export` 命令将一个 `shell` 变量**导出/提升为环境变量** ```shell # 方式一: 先定义变量, 再导出 MYVAR="Hello World" export MYVAR # 方式二: 定义变量的同时将其导出 export MYVAR="Hello World" ``` 如果希望环境变量**在系统重启后依然可用**,作为 **==用户级的或系统级别的全局环境变量==**,则需要在相应的配置文件中去定义该环境变量: - **==用户级==环境变量**:需要将其添加到**用户的"登录配置文件"** 或 "**用户级的 shell 配置文件**" **中,`~/.bash_profile` 、 `~/.profile`、`~/.bash_login`(取决于所用 Shell 和操作系统)或 `~/.bashrc` 中。 此后每次用户登录时,变量就会自动设置。 - **==系统级==环境变量**:需要将其添加到"**系统级的登录配置文件**" 或 "**系统级的 shell 配置文件**"中,如 `/etc/profile`、`/etc/bash.bashrc` 或 `/etc/bashrc` ,或者作为脚本放到 `/etc/profile.d/` 目录中。 <br><br><br> # 变量操作 ### 查看环境变量 shell 中查看环境变量的几种方法: - **`env` 或 `printenv` 命令**:二者功能几乎相同,都用于**显示当前用户的==环境变量**==,会**列出所有环境变量及其值** - 可查看**特定的环境变量**,如 `printenv HOME` 或 `env | grep HOME` 或 `echo $HOME` - **`set` 命令**:显示**当前 shell 进程**中的**所有 shell 变量**和**函数**,包括环境变量、用户自定义的局部变量等。 - **`echo` 命令**:可用于**查看指定环境变量的值**,例如 `echo $PATH` 会显示 `PATH` 环境变量的内容。 - 使用 **bash 内置命令** `declare -p` 或 `typeset- p` : > bash 内置命令 `declare -p <VAR>` 或 `typeset -p <VAR>` 将以 "**声明**" 的形式来打印指定环境变量的值, > 输出格式为 `declare -x VAR="value"`。 > ![[_attachment/02-开发笔记/11-Linux/shell 相关/shell 变量.assets/IMG-shell 变量-67D00949E167616F15D07B97F973E0BA.png]] ### 使用变量 shell 脚本中**引用变量值**的两种方式: - `$variable` - `${variable}` 带花括号,显式界定 `
后的变量名。 **引用变量值**时需要使用 `
,而**对变量赋值**时不需要使用 `
。 在一些特殊语法,例如 **`$(())` 算术表达式**或 **C 风格的 `for` 循环**中使用变量值时无需带 `
或 `${}`。 ### 删除变量 使用 `unset` 命令将从 "当前 shell 会话" 中完全移除变量。 > [!NOTE] 如果是在子进程中删除一个环境变量,则该操作仅对子进程有效。该环境变量在父进程中依然存在且有效。 ```sh unset variable ``` ### 变量扩展 在 Bash 和其他类 Unix shell 中,提供了一系列"**高级变量扩展**"的机制,**支持使用特定语法来操作或提取变量的内容**,包括字符串操作、条件检查等。 最基本的变量扩展即是通过 `
或 `${}` 来引用变量值。 **高级变量扩展**提供了更多功能,包括: - **获取"变量内容"的长度** - `${#var}` - **==间接引用==** / **==动态变量名==**:使用动态构造的变量名 - `${!var}` ,首先获取"变量 var 的值",将这一值 (`$var`) 作为"**变量名**"再**引用该变量的值**。 - **指定默认值**: - 如果变量**未定义或为空**,使用默认值。 - `${var:-default_value}` - 如果变量**未定义**,使用默认值(变量为空字符串时,不会使用默认值) - `${var-default_value}` - **子字符串提取**:从变量中提取子字符串 - `${variable:position:length}` - **替换**:在变量内容中替换字符串 - `${var/search/replace}` - **条件检查**:基于变量的状态执行不同操作 - 如果变量**未定义或为空**,则**使用指定的默认值**: `:-` - `${var:-"default_value"}` - 如果变量**未定义或为空**,则 **将变量==赋值==为指定的默认值**: `:=` - `${var:="default_value"}` - 如果变量==**已设置且非空**==,则使用指定的值:`:+` - `${var:+"assigned_value"}` - 如果变量**未定义或为空**,则**打印错误消息并退出当前脚本** - `${var:?"error_message"}` - **大小写转换**(Bash 4 及以上版本):变量内容的大小写转换。 ```shell ${var^} # 首字母大写 ${var^^} # 全字母大写 ${var,} # 首字母小写 ${var,,} # 全字母小写 ``` <br><br> # bash shell 特殊变量 Bash Shell 提供了许多特殊变量,这些变量用于特定的用途,如存储命令的结果、表示当前 Shell 环境的状态等。下面是一些在 Bash 中最常用的特殊变量及其说明: ```shell $0 # 当前脚本的名称 $1~$9, ${10}... # 命令行参数 $# # 传递给脚本的参数个数 $@ # 所有传递给脚本的参数的列表。当被双引号包围时,$@会保持参数之间的分隔,即使参数中包含空格。 $* # 所有传递给脚本的参数的列表,作为"单个字符串"。当被双引号包围时,所有参数被视为一个整体。 $? # 上一个命令的退出状态码。成功执行返回0, 失败返回非0值 $_ # 上一个命令的最后一项参数 $ # 当前shell进程的PID $! # 最后一个在后台运行的命令的PID $- # 当前shell的选项, 由启动时或使用`set`命令设置的标志组成 ``` - `$*` 用在**双引号内**时,会被扩展成**由多个命令行参数组成的单个单词**,每个单词之间以 `IFS` 变量值的首个字符 `c` 分隔,即 `"$*"` 会被扩展成 `"$1c$2c$3c..."` - `$@` 用在**双引号内**时,其所包含的各个命令行参数会被**扩展成独立的单词**,`"$@"` 会被扩展成 `"$1""$2""$3"...`。 ```shell #!/bin/bash echo "Starting program at $(date)" # Date will be substituted echo "Running program $0 with $# arguments with pid $" for file in "$@"; do grep foobar "$file" > /dev/null 2> /dev/null # When pattern is not found, grep has exit status 1 # We redirect STDOUT and STDERR to a null register since we do not care about them if [[ $? -ne 0 ]]; then echo "File $file does not have any foobar, adding one" echo "# foobar" >> "$file" fi done ``` <br><br><br> # 通用环境变量 ### 通用环境变量 ```shell $IFS # 内部字段分隔符. 默认包括空格、制表符和换行符 $PATH # shell 查找命令时使用的目录列表, 以冒号分隔 $PWD # 当前工作目录 $HOME # 当前用户的家目录 $USER # 当前用户的用户名 $HOSTNAME # 当前机器的主机名 $RANDOM # 返回一个随机整数 $SECONDS # 自脚本开始运行以来的秒数 $LINENO # 当前脚本中的行号 $SHELL # 当前用户的默认 shell $TERM # 当前终端的类型 $EDITOR # 用户默认的文本编辑器 $VISUAL # 用户默认的文本编辑器 ``` ### shell 特有环境变量 bash shell 中自带一些默认的特定的环境变量来定义系统环境,包括: - **Unix Bourne shell 中定义的环境变量**(由于 bash shell 源自最初的 Unix Bourne shell,因此进了保留) > ![image-20240103133032543|621](_attachment/02-开发笔记/11-Linux/shell%20相关/shell%20变量.assets/IMG-shell%20变量-CD5D84180415F55F55958CD4AF558A61.png) - **Bash shell 特有的自带环境变量** > ![image-20240103133054326|539](_attachment/02-开发笔记/11-Linux/shell%20相关/shell%20变量.assets/IMG-shell%20变量-307994B9B1CBEBF7476FF3BFC6969949.png) ![image-20240103133315786|547](_attachment/02-开发笔记/11-Linux/shell%20相关/shell%20变量.assets/IMG-shell%20变量-820198265DAD9A91C52A8CD97860E992.png) > ![image-20240103133404288|549](_attachment/02-开发笔记/11-Linux/shell%20相关/shell%20变量.assets/IMG-shell%20变量-BEA88E9EABC56D86614F5343B6704436.png) > ![image-20240103133424784|552](_attachment/02-开发笔记/11-Linux/shell%20相关/shell%20变量.assets/IMG-shell%20变量-620E46C47E4E309CBA93B057ECCC6E44.png) # 参考资料 # Footnotes