跳到主要内容
Linux Shell 变量的定义与使用方法 | 极客日志
Shell / Bash java
Linux Shell 变量的定义与使用方法 Shell 变量用于存储数据,无需声明类型。支持基本赋值、算术运算及字符串处理。通过 export 可导出为环境变量供子进程使用。位置参数接收命令行输入。提供默认值设置、错误提示及模式匹配扩展功能。作用域默认为全局,函数内可用 local 限制。数组支持一维动态操作。调试可使用 set -x 或 declare。常见陷阱包括空格、引号缺失及未初始化变量。结合 Java 对比理解动态类型特性,有助于掌握脚本编写规范与最佳实践。
SecGuard 发布于 2026/3/30 更新于 2026/6/2 20 浏览Linux Shell 变量的定义与使用方法
在 Linux 系统中,Shell 脚本是自动化任务、系统管理、部署运维的核心工具之一。变量作为脚本中最基础也是最重要的元素之一,掌握其定义与使用方法,是每一个 Linux 用户和开发者必须跨越的第一道门槛。
什么是 Shell 变量?
在 Shell 环境中,变量(Variable)是用来存储数据的一个命名容器。你可以把它想象成一个贴了标签的盒子,里面可以放字符串、数字、命令输出等信息。当你需要重复使用某个值或动态改变程序行为时,变量就派上了用场。
与编译型语言如 C++ 或 Java 不同,Shell 是一种解释型脚本语言,它的变量无需声明类型,也不强制初始化——这既是它的灵活性所在,也是容易出错的地方。
示例:
name="Alice"
age=25
echo "Hello, $name ! You are $age years old."
输出:
Hello, Alice! You are 25 years old.
Shell 变量的定义方式
1. 基本赋值语法
在 Shell 中,变量赋值使用 = 符号,注意等号两边不能有空格!
username="root"
2. 变量名命名规则
只能包含字母、数字和下划线 _
不能以数字开头
区分大小写
通常建议使用小写字母(避免与系统环境变量冲突)
my_var=100
_my_private=secret
2nd_try=fail
MY_VAR=value
3. 字符串赋值
字符串可以用单引号 ' 或双引号 " 包裹:
单引号 :内容原样输出,不解析变量或转义字符
双引号 :允许变量替换和部分转义字符(如 \n, \t)
name="Bob"
msg1='Hello $name'
msg2="Hello "
$name
echo
"$msg1 "
echo
"$msg2 "
数值变量与算术运算 虽然 Shell 变量默认是字符串类型,但你可以通过特定语法进行数值计算。
使用 $(( )) 进行整数运算 a=10
b=3
sum =$((a + b))
product=$((a * b))
mod=$((a % b))
echo "Sum: $sum "
echo "Product: $product "
echo "Mod: $mod "
使用 expr 命令(较老的方式) result=$(expr 5 + 3)
echo $result
⚠️ 注意:expr 对空格敏感,操作符两侧必须有空格!
变量的作用域:局部 vs 全局 在 Shell 中,变量默认是全局变量,可以在当前 Shell 及其子进程中访问。若想限制变量作用域,可使用 local 关键字(仅在函数内有效)。
#!/bin/bash
global_var="I am global"
my_function (){
local local_var="I am local"
echo "Inside function: $global_var "
echo "Inside function: $local_var "
}
my_function
echo "Outside function: $global_var "
echo "Outside function: $local_var "
环境变量与 export 命令 环境变量是被导出(export)给子进程使用的全局变量。常见的环境变量如 PATH, HOME, USER 等。
查看所有环境变量
导出自定义变量 MY_APP_HOME="/opt/myapp"
export MY_APP_HOME
export JAVA_HOME="/usr/lib/jvm/java-11-openjdk"
在子 Shell 中继承 export SECRET_KEY="abc123"
bash -c 'echo "Child shell sees: $SECRET_KEY"'
从命令行接收变量:位置参数 Shell 脚本可以通过 $1, $2, …, $9, ${10}, ${11} 等接收命令行传入的参数。
#!/bin/bash
echo "Script name: $0 "
echo "First arg: $1 "
echo "Second arg: $2 "
echo "Number of args: $# "
echo "All args: $*"
./myscript.sh apple banana cherry
Script name: ./myscript.sh
First arg: apple
Second arg: banana
Number of args: 3
All args: apple banana cherry
特殊变量一览表 变量名 含义 $0脚本名称 $1~$9第 1 到第 9 个参数 ${10}+第 10 个及以上参数需加大括号 $#参数个数 $*所有参数作为一个字符串 $@所有参数作为独立字符串(推荐用于遍历) $?上一条命令的退出状态码(0 表示成功) $$当前 Shell 进程 ID $!最后一个后台进程的 PID
#!/bin/bash
echo "PID: $$"
sleep 5 &
bg_pid=$!
echo "Background job PID: $bg_pid "
wait $bg_pid
echo "Job finished with status: $?"
变量的扩展与替换 Shell 提供了强大的变量扩展功能,让你可以在不调用外部命令的情况下处理字符串。
1. 默认值设置 ${var:-default} echo ${USER_NAME:-"Guest"}
2. 设置默认值 ${var:=default}
3. 错误提示 ${var:?message} echo ${REQUIRED_VAR:?"Required variable is missing!"}
4. 字符串截取 str="hello_world.txt"
echo ${str:0:5}
echo ${str:6}
echo ${str: -3}
5. 模式匹配替换 filename="document_v2.pdf"
echo ${filename%.pdf}
echo ${filename#*_}
echo ${filename/doc/DOC}
Shell 变量生命周期 阶段 说明 Shell 启动 变量定义前不可用 定义变量 var=value 变量进入当前 Shell 环境 是否 export? 决定是否为环境变量 成为环境变量 可被子进程继承 仅当前 Shell 可用 非导出变量,子进程不可见 函数或子进程中不可见 local 变量仅限函数内 脚本结束或 unset 删除 变量销毁
Shell 变量调试技巧
1. 使用 set -x 开启调试模式 #!/bin/bash
set -x
name="Debug Mode"
echo "Hello $name "
set +x
+ name='Debug Mode'
+ echo 'Hello Debug Mode'
Hello Debug Mode
+ set +x
2. 使用 declare 查看变量属性
3. 使用 typeset 或 declare 定义带类型的变量(Bash 特有) declare -i num=10
declare -r const="immutable"
declare -a arr=("a" "b" "c" )
const="new value"
数组变量的使用
定义数组 fruits=("apple" "banana" "cherry" )
nums=(1 2 3 4 5)
访问元素 echo ${fruits[0]}
echo ${fruits[1]}
echo ${fruits[@]}
echo ${#fruits[@]}
遍历数组 for fruit in "${fruits[@]} " ; do
echo "I like $fruit "
done
添加元素 fruits+=("orange" )
fruits[${#fruits[@]} ]="grape"
Shell 变量 vs Java 变量:对比学习 为了帮助 Java 开发者更快上手 Shell 变量,我们做一个对比表格:
特性 Shell 变量 Java 变量 类型声明 无类型,动态 必须声明类型(int, String 等) 初始化 可选 局部变量必须初始化 作用域 默认全局,可用 local 限制 由 {} 块决定 命名规范 推荐小写,避免大写 驼峰命名法(camelCase) 字符串拼接 直接连接或使用 "$a$b" 使用 + 或 StringBuilder 环境变量 通过 export 导出 通过 System.getenv() 读取 数组 一维,动态 多维,固定长度或使用 ArrayList 调试 set -x, echoIDE 断点、日志框架
Java 代码示例:模拟 Shell 变量行为 下面是一个 Java 类,模拟 Shell 变量的基本行为——动态类型、字符串存储、支持默认值等。
import java.util.HashMap;
import java.util.Map;
public class ShellVariableSimulator {
private Map<String, String> variables = new HashMap <>();
public void set (String key, String value) {
variables.put(key, value);
}
public String get (String key, String defaultValue) {
return variables.getOrDefault(key, defaultValue);
}
public String get (String key) {
return variables.get(key);
}
public String getDefault (String key, String fallback) {
String val = variables.get(key);
return (val == null || val.isEmpty()) ? fallback : val;
}
public String setDefault (String key, String fallback) {
if (!variables.containsKey(key) || variables.get(key).isEmpty()) {
variables.put(key, fallback);
}
return variables.get(key);
}
public String require (String key, String errorMessage) throws RuntimeException {
String val = variables.get(key);
if (val == null || val.isEmpty()) {
throw new RuntimeException (errorMessage);
}
return val;
}
public void printAll () {
variables.forEach((k, v) -> System.out.println(k + " = " + v));
}
public static void main (String[] args) {
ShellVariableSimulator sim = new ShellVariableSimulator ();
sim.set("USER" , "john_doe" );
sim.set("TEMP_DIR" , "" );
System.out.println("USER: " + sim.get("USER" , "guest" ));
System.out.println("HOST: " + sim.get("HOST" , "localhost" ));
System.out.println("TEMP_DIR or /tmp: " + sim.getDefault("TEMP_DIR" , "/tmp" ));
sim.setDefault("LOG_LEVEL" , "INFO" );
System.out.println("LOG_LEVEL: " + sim.get("LOG_LEVEL" ));
try {
sim.require("REQUIRED_CONFIG" , "配置项 REQUIRED_CONFIG 不能为空!" );
} catch (RuntimeException e) {
System.out.println("错误:" + e.getMessage());
}
System.out.println("\n--- 所有变量 ---" );
sim.printAll();
}
}
USER: john_doe
HOST: localhost
TEMP_DIR or /tmp: /tmp
LOG_LEVEL: INFO
错误:配置项 REQUIRED_CONFIG 不能为空!
--- 所有变量 ---
USER = john_doe
TEMP_DIR =
LOG_LEVEL = INFO
这个模拟器虽然简化了很多 Shell 特性(比如数组、算术扩展、命令替换等),但它清晰地展示了 Shell 变量'动态'、'字符串为中心'、'默认值机制'的核心思想。
高级技巧:变量间接引用 有时候你需要通过一个变量的名字去访问另一个变量的值,这就叫'间接引用'。
使用 ${!var} 语法 name="Alice"
ref="name"
echo ${!ref}
动态构造变量名 prefix="user_"
for i in {1..3}; do
var_name="${prefix} ${i} "
declare "$var_name =Person$i "
done
echo $user_1
echo $user_2
echo $user_3
变量清理:unset 命令 不再需要的变量应及时清理,尤其是大型脚本中,避免命名冲突或内存浪费。
temp_data="some sensitive info"
echo $temp_data
unset temp_data
echo $temp_data
实战案例:构建配置加载器 下面我们编写一个简单的 Shell 脚本,从 .env 文件加载配置到环境变量中,类似 Docker Compose 的行为。
DB_HOST =localhost
DB_PORT =5432
DB_USER =admin
DB_PASS =secret123
DEBUG =true
#!/bin/bash
CONFIG_FILE=".env"
if [[ ! -f "$CONFIG_FILE " ]]; then
echo "配置文件 $CONFIG_FILE 不存在!"
exit 1
fi
while IFS='=' read -r key value; do
[[ -z "$key " ]] && continue
[[ "$key " =~ ^[[:space:]]*# ]] && continue
key=$(echo "$key " | xargs)
value=$(echo "$value " | xargs)
export "$key =$value "
echo "Loaded: $key = $value "
done < "$CONFIG_FILE "
echo "✅ 配置加载完成!共加载 $(printenv | grep -E '^(DB_|DEBUG) ' | wc -l) 个变量。"
Loaded: DB_HOST = localhost
Loaded: DB_PORT = 5432
Loaded: DB_USER = admin
Loaded: DB_PASS = secret123
Loaded: DEBUG = true
✅ 配置加载完成!共加载 5 个变量。
Shell 变量常见陷阱与避坑指南
1. 空格陷阱
2. 引号缺失导致单词分割 file_path="/home/user/my file.txt"
cat $file_path
cat "$file_path "
3. 未初始化变量导致意外行为
echo $((count + 1 ))
count=0
echo $((count + 1 ))
4. 变量名拼写错误难以发现 usre_name="Bob"
echo "Hello $username "
set -u
单元测试你的 Shell 变量逻辑 虽然 Shell 没有像 JUnit 那样的测试框架,但你可以用简单的 if 判断和 exit 来做基本验证。
#!/bin/bash
test_variable_default () {
local test_val=${UNDEFINED_VAR:-"default"}
if [[ "$test_val " != "default" ]]; then
echo "❌ Test failed: expected 'default', got '$test_val '"
exit 1
fi
echo "✅ Test passed: default value works"
}
test_variable_set_default () {
unset TEST_VAR
local result=${TEST_VAR:="fallback"}
if [[ "$result " != "fallback" ]]; then
echo "❌ Test failed: expected 'fallback', got '$result '"
exit 1
fi
echo "✅ Test passed: set-default works"
}
test_variable_require () {
unset REQUIRED
if output=$({ require_var "REQUIRED" "Missing!" ;} 2>&1); then
echo "❌ Test failed: should have thrown error"
exit 1
else
echo "✅ Test passed: required variable check works"
fi
}
require_var () {
local var_name=$1
local msg=$2
if [[ -z "${!var_name} " ]]; then
echo "$msg " >&2
return 1
fi
}
test_variable_default
test_variable_set_default
test_variable_require
echo "🎉 All tests passed!"
Shell 变量在 DevOps 中的实际应用 在现代 DevOps 流程中,Shell 变量无处不在:
CI/CD 流水线 :Jenkins、GitLab CI 中通过环境变量传递构建参数
容器化部署 :Docker、Kubernetes 使用环境变量配置服务
云平台集成 :AWS CLI、Azure CLI 依赖环境变量认证
自动化脚本 :备份、监控、日志清理等任务都依赖变量控制行为
deploy_prod:
script:
- echo "Deploying version $CI_COMMIT_TAG to $DEPLOY_ENV"
- ./deploy.sh --env $DEPLOY_ENV --version $CI_COMMIT_TAG
environment:
name: production
这里的 $CI_COMMIT_TAG 和 $DEPLOY_ENV 就是典型的 Shell 环境变量。
性能考量:变量 vs 命令替换
for i in {1..1000}; do
echo "Time: $(date) "
done
now=$(date )
for i in {1..1000}; do
echo "Time: $now "
done
总结:Shell 变量的最佳实践
命名清晰 :使用有意义的小写变量名,如 backup_dir, max_retries
及时初始化 :避免未定义行为,尤其在算术运算中
合理使用引号 :防止单词分割和路径空格问题
限制作用域 :在函数中使用 local 避免污染全局空间
清理无用变量 :用 unset 释放资源
启用严格模式 :set -u、set -e 提高脚本健壮性
善用默认值 :${var:-default} 避免空值异常
避免硬编码 :把配置提取为变量,提高脚本复用性
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online