比较符
英文短语的缩写,含义清晰:
| 操作符 | 英文全称 | 中文含义 |
|---|---|---|
-eq | equal | 等于 |
-ne | not equal | 不等于 |
-lt | less than | 小于 |
-le | less or equal | 小于等于 |
-gt | greater than | 大于 |
-ge | greater or equal | 大于等于 |
环境变量
| 环境变量 | 描述 |
|---|---|
BASHPID | Bash 进程的进程 ID。 |
EDITOR | 默认的文本编辑器。 |
HOME | 用户的主目录。 |
HOST | 当前主机的名称。 |
LANG | 字符集以及语言编码,比如 zh_CN.UTF-8。 |
PATH | 由冒号分开的目录列表,当输入可执行程序名后,会搜索这个目录列表。 |
PWD | 当前工作目录。 |
SHELL | Shell 的名字。 |
TERM | 终端类型名,即终端仿真器所用的协议。 |
UID | 当前用户的 ID 编号。 |
USER | 当前用户的用户名。 |
文件测试参数
| 参数 | 说明 |
|---|---|
-e | 文件存在(最常用) |
-f | 文件存在且是普通文件(不是目录或链接) |
-d | 文件存在且是目录 |
-r | 文件存在且可读 |
-w | 文件存在且可写 |
-x | 文件存在且可执行 |
变量
在 Linux Shell(主要是 Bash)中,变量的使用非常灵活,但有一个核心规则必须记住:赋值时不能有空格,引用时要加 $ 符号。
定义变量
语法:变量名=值;关键点:等号 = 两边绝对不能有空格。
# ✅ 正确写法
name="Alice"
age=25
url=https://www.example.com
message='Hello World'
# ❌ 错误写法 (会报错:command not found)
# name = "Alice" (空格会导致 shell 把 name 当作命令执行)
# age= 25
引号的使用:"允许变量替换和命令替换(推荐常用)。
greeting="Hello, $name" # 这里的 $name 会被解析为 Alice
单引号:'不进行任何替换,内容原样输出。
greeting='Hello, $name' # 输出就是字面量 "Hello, $name"
无引号:如果值中没有空格或特殊字符,可以不加引号;如果有空格,必须加引号。
city=Beijing # ✅ 可行
city="New York" # ✅ 必须加引号,否则 shell 会把 York 当作另一个参数
使用变量
语法:$变量名 或 ${变量名}
name="Bob"
# 方法 1:直接加 $
echo $name
# 输出: Bob
# 方法 2:加大括号 (推荐,更清晰,避免歧义)
echo ${name}
# 输出: Bob
为什么要用 ${};当变量名后面紧跟着其他字符时,必须用大括号区分。
file="report"
# ❌ 错误:shell 会尝试找名为 filetxt 的变量
echo $filetxt
# ✅ 正确:明确告诉 shell 变量名是 file,后面紧跟 txt
echo ${file}txt
# 输出: report.txt
特殊变量
Shell 内置了一些特殊变量,用于脚本控制:
| 变量 | 含义 | 示例 |
|---|---|---|
$0 | 当前脚本的名称 | ./myscript.sh |
$1, $2... | 第 1、第 2 个位置参数 | ./script.sh arg1 arg2 ($1是arg1) |
$# | 传递给脚本的参数个数 | echo $# |
$? | 上一个命令的退出状态码 (0 表示成功,非 0 表示失败) | ls /tmp; echo $? |
$$ | 当前 Shell 进程的 PID | |
$HOME | 当前用户的主目录 | |
$PATH | 可执行程序的搜索路径 |
变量的运算
Shell 默认将变量视为字符串,进行数学运算需要特殊语法。
- 整数运算:使用
(( ))或$[ ]或expr(推荐(( ))):
a=10
b=5
# 方法 1:双括号 (推荐)
sum=$((a + b))
echo $sum # 输出: 15
# 方法 2:let 命令
let c=a*b
echo $c # 输出: 50
- 字符串拼接:直接连写即可。
first="Hello"
second="World"
full="${first} ${second}"
echo $full # 输出: Hello World
- 删除变量:使用
unset命令
my_var="test"
echo $my_var # 输出: test
unset my_var
echo $my_var # 输出: (空)
- 环境变量 vs 局部变量 局部变量:只在当前 Shell 会话或脚本中有效。
name="Alice"
- 环境变量:可以传递给子进程(如在脚本中调用的其他命令)。需要使用
export。
export NAME="Alice"
# 或者
NAME="Alice"
export NAME
实战示例脚本:创建一个名为 test_var.sh 的文件:
#!/bin/bash
# 1. 定义变量
user="Root"
count=1
log_file="/var/log/syslog"
# 2. 使用变量
echo "当前用户: $user"
echo "登录次数: $((count + 5))" # 运算
# 3. 检查上一个命令是否成功
ls /etc/hosts
if [ $? -eq 0 ]; then
echo "文件存在 (退出码: $?)"
else
echo "文件不存在"
fi
# 4. 使用位置参数 (运行脚本时传入)
# 运行方式: ./test_var.sh param1 param2
echo "第一个参数: $1"
echo "第二个参数: $2"
echo "参数总数: $#"
# 5. 字符串拼接
full_path="${HOME}/projects/${user}_data"
echo "完整路径: $full_path"
常见坑点总结
- 空格陷阱:
var = 1是错的,必须是var=1。 - 引用陷阱:
echo $var如果 var 里有空格,最好写成echo "$var",否则单词会被拆分。 - 只读变量:可以用
readonly var_name锁定变量,防止被修改。 - 命令输出赋值:可以使用反引号
`cmd`或$(cmd)。
current_date=$(date)
file_list=$(ls -l)
if条件判断
if [ 条件测试 ] # 条件测试左右必须要有空格
then
...
fi # 结束符
或者
if [ 条件测试 ]; then
...
fi
if [ 条件测试 ]
then
...
else
...
fi
if [ 条件表达式 ]; then
# 条件成立时执行的命令
elif [ 另一个条件表达式 ]; then
# 另一个条件成立时执行的命令
else
# 以上条件都不成立时执行的命令
fi
- 判断数字大小与文件属性
#!/bin/bash
# 定义变量
num=20
file_name="v1.txt"
echo "### 开始执行 if 语句演示 ###"
# 1. 数值比较
# -eq 表示等于
if [ $num -eq 10 ]; then
echo "数字等于 10"
# -gt 表示大于
elif [ $num -gt 15 ]; then
echo "数字大于 15 (当前值为 $num)"
else
echo "数字小于 15"
fi
# 2. 文件属性判断
echo -e "\n### 文件检查 ###"
# -e 表示文件是否存在
if [ -e "$file_name" ]; then
echo "$file_name 存在。"
# -f 表示是否为普通文件(不是目录)
if [ -f "$file_name" ]; then
echo "这是一个普通文件。"
fi
else
echo "$file_name 不存在,请先创建。"
fi
for循环
for 循环通常用于遍历一组数据(如数字序列、字符串列表或文件内容)。
for 变量 in 列表
do
# 循环体命令
done
- 遍历数字与读取文件行
#!/bin/bash
echo "### 开始执行 for 循环演示 ###"
# 1. 遍历数字序列 (1 到 5)
# -e 参数的作用是启用反斜杠转义
echo -e "\n-- 打印数字 1 到 5 --"
for i in {1..5}
do
echo "当前数字是: $i"
done
# 2. 遍历文件中的每一行 (基于你之前的 v1.txt)
echo -e "\n-- 读取 v1.txt 文件内容 --"
# 使用 < $file 让 while 读取文件,这是更稳健的写法,但 for 也可以用 cat
for line in $(cat v1.txt)
do
# 注意:这种方式会按空格分割单词,如果想按整行读取,请看 while 演示
echo "读取到: $line"
done
while循环
while [ 条件表达式 ]
do
# 循环体命令
done
- 读取文件与计数
#!/bin/bash
echo "### 开始执行 while 循环演示 ###"
# 1. 读取文件的每一行 (推荐用于读取文件)
echo -e "\n-- 逐行读取 v1.txt (保留空格) --"
count=1
# read line 会从标准输入读取一行赋值给 line
while read line
do
echo "第 $count 行: $line"
# ((count++)) 是 shell 中的自增写法
((count++))
done < v1.txt
# 2. 简单计数器
echo -e "\n-- 倒计时 (5 到 1) --"
i=5
while [ $i -gt 0 ]
do
echo "$i..."
sleep 1 # 暂停 1 秒
i=$((i - 1))
done
echo "倒计时结束!"
case多分支选择
case 语句类似于其他语言的 switch,用于匹配变量的值并执行相应操作,非常适合处理用户输入。
case $变量 in
模式1)
# 命令1
;;
模式2)
# 命令2
;;
*)
# 默认命令 (相当于 else)
;;
esac
- 菜单选择
#!/bin/bash
# 假设这是用户输入的参数,$1 代表第一个命令行参数
# 你可以运行脚本时加参数,例如:./script.sh start
action="$1"
echo "### 开始执行 case 语句演示 ###"
case $action in
"start")
echo "正在启动服务..."
# 这里可以放启动命令
;;
"stop")
echo "正在停止服务..."
;;
"restart")
echo "正在重启服务..."
;;
"status")
echo "正在查询服务状态..."
;;
*)
echo "错误:无效的命令"
echo "用法: $0 {start|stop|restart|status}"
# $0 代表脚本名本身
;;
esac
逻辑运算符
&& 逻辑与
只有当左边的命令执行成功(返回值为 0)时,才执行右边的命令。前真后执行。
# 如果 v1.txt 存在,则删除它
[ -f v1.txt ] && rm v1.txt
|| 逻辑或
只有当左边的命令执行失败(返回值非 0)时,才执行右边的命令。前假后执行。
# 如果 v1.txt 不存在(grep 失败),则创建一个新文件
grep "hello" v1.txt || touch v1.txt
! 逻辑非
对判断结果取反。
# 如果 v1.txt 不存在
if [ ! -f v1.txt ]; then
echo "文件没找到"
fi
函数
函数的定义
方法 1:使用 function 关键字(推荐,更清晰)
# function my_function 这里的()可以不写,但是不建议
function my_function() {
echo "这是函数内部"
# 可以放多条命令
}
方法 2:使用括号语法(传统写法)
my_function() {
echo "这也是函数"
}
函数的调用
定义后,直接使用函数名调用,不需要加括号:
my_function # 调用函数
完整脚本
#!/bin/bash
function greet() {
echo "你好,欢迎使用 Shell 脚本!"
}
greet # 输出:你好,欢迎使用 Shell 脚本!
函数参数传递
局部变量与全局变量:默认变量是全局的,函数内外都可访问。 使用 local 关键字声明局部变量,仅在函数内部有效。
示例:局部变量
function test_localVar() {
local var="局部变量"
echo "函数内:$var"
}
var="全局变量"
test_localVar
echo "函数外:$var" # 仍输出“全局变量”
函数可以接收参数,使用方式与脚本参数相同:
$1、$2、$3...:表示第 1、2、3 个参数$#:参数个数$@或$*:所有参数$0:脚本名(在函数中仍表示脚本名,不是函数名) 示例:带参数的函数
function greet_user {
local name=$1
local age=$2
echo "你好,$name!你今年 $age 岁。"
}
greet_user "小明" 20
# 输出:你好,小明!你今年 20 岁。
函数返回值
Shell 函数不能像其他语言那样“返回字符串或数字”,它只能通过 return 返回退出状态码(0~255),通常:
return 0:表示成功return 1:表示失败 如果要返回实际数据(如字符串、计算结果),应使用echo输出,然后用命令替换获取。
- 示例:返回状态码
function check_file() {
if [ -f "$1" ]; then
return 0 # 成功
else
return 1 # 失败
fi
}
check_file "test.txt"
if [ $? -eq 0 ]; then
echo "文件存在"
else
echo "文件不存在"
fi
- 示例:返回实际值(推荐做法)
function add() {
local sum=$(( $1 + $2 ))
echo $sum # 用 echo 输出结果
}
result=$(add 3 5)
echo "结果是:$result" # 输出:结果是:8
函数的嵌套与作用域
函数可以嵌套定义(不推荐),也可以在函数中调用其他函数:
function outer() {
echo "外层函数"
inner
}
function inner() {
echo "内层函数"
}
outer
# 输出:
# 外层函数
# 内层函数
实用技巧
- 函数参数校验
function divide() {
if [ $# -ne 2 ]; then
echo "用法:divide <被除数> <除数>"
return 1
fi
if [ $2 -eq 0 ]; then
echo "错误:除数不能为 0"
return 1
fi
echo $(( $1 / $2 ))
}
divide 10 2 # 输出:5
divide 10 0 # 输出错误信息
- 函数库复用:可以把常用函数写入一个文件,如
lib.sh:
# lib.sh
function log_info() {
echo "[INFO] $1"
}
function log_error() {
echo "[ERROR] $1" >&2
}
在主脚本中引入:
#!/bin/bash
source ./lib.sh # 或 . ./lib.sh
log_info "程序开始"
log_error "发生错误"
函数调试技巧
使用 set -x 开启调试模式,可看到函数执行过程:
set -x
my_function
set +x