Shell 脚本基础
什么是 Shell 脚本?
Shell 脚本是包含一系列命令的文本文件,由 Shell 解释执行。它可以自动化重复性任务、批量处理文件、管理系统等。
创建第一个脚本
编写脚本
bash
#!/bin/bash
# 我的第一个脚本
# 作者:Maxwell
# 日期:2025-01-09
echo "Hello, World!"
echo "当前时间: $(date)"
echo "当前用户: $USER"
echo "当前目录: $PWD"Shebang
脚本第一行的 #! 称为 Shebang,指定解释器:
bash
#!/bin/bash # 使用 bash
#!/bin/sh # 使用 sh
#!/usr/bin/env bash # 推荐,使用环境中的 bash
#!/usr/bin/env python3 # Python 脚本运行脚本
bash
# 方法 1:添加执行权限
$ chmod +x script.sh
$ ./script.sh
# 方法 2:使用 bash 运行
$ bash script.sh
# 方法 3:使用 source(在当前 Shell 执行)
$ source script.sh
$ . script.sh变量
定义和使用变量
bash
#!/bin/bash
# 定义变量(等号两边不能有空格)
name="Maxwell"
age=25
path="/home/maxwell"
# 使用变量
echo "Name: $name"
echo "Age: ${age}"
echo "Path: ${path}/documents"
# 只读变量
readonly PI=3.14159
# 删除变量
unset age变量类型
bash
# 字符串
str="Hello World"
# 数字(实际上都是字符串)
num=42
# 数组
arr=(one two three)
echo ${arr[0]} # one
echo ${arr[@]} # 所有元素
echo ${#arr[@]} # 数组长度特殊变量
| 变量 | 说明 |
|---|---|
$0 | 脚本名称 |
$1-$9 | 位置参数 |
${10} | 第 10 个及以后的参数 |
$# | 参数个数 |
$@ | 所有参数(作为独立字符串) |
$* | 所有参数(作为单个字符串) |
$? | 上一个命令的退出状态 |
$$ | 当前脚本的 PID |
$! | 最后一个后台进程的 PID |
bash
#!/bin/bash
echo "脚本名: $0"
echo "第一个参数: $1"
echo "第二个参数: $2"
echo "参数个数: $#"
echo "所有参数: $@"字符串操作
bash
str="Hello World"
# 长度
echo ${#str} # 11
# 子串
echo ${str:0:5} # Hello
echo ${str:6} # World
# 替换
echo ${str/World/Bash} # Hello Bash
echo ${str//o/O} # HellO WOrld(全部替换)
# 删除
filename="document.txt.bak"
echo ${filename%.bak} # document.txt(从右删除)
echo ${filename%%.*} # document(贪婪)
echo ${filename#*.} # txt.bak(从左删除)
echo ${filename##*.} # bak(贪婪)
# 默认值
echo ${undefined:-default} # 变量未定义时使用默认值
echo ${undefined:=default} # 未定义时设置默认值
echo ${undefined:?error msg} # 未定义时报错引号
单引号
单引号内的内容原样输出,不解析变量:
bash
name="Maxwell"
echo 'Hello $name' # Hello $name双引号
双引号内解析变量和命令替换:
bash
name="Maxwell"
echo "Hello $name" # Hello Maxwell
echo "Today is $(date +%Y-%m-%d)"反引号和 $()
命令替换:
bash
# 反引号(旧语法)
today=`date +%Y-%m-%d`
# $()(推荐)
today=$(date +%Y-%m-%d)
files=$(ls -la)算术运算
$(()) 语法
bash
a=10
b=3
echo $((a + b)) # 13
echo $((a - b)) # 7
echo $((a * b)) # 30
echo $((a / b)) # 3
echo $((a % b)) # 1
echo $((a ** b)) # 1000(幂运算)
# 自增自减
((a++))
((b--))
((a += 5))let 命令
bash
let "a = 10 + 5"
let "a++"expr 命令
bash
result=$(expr 10 + 5)
result=$(expr 10 \* 5) # 乘法需要转义bc 计算器(浮点数)
bash
# 整数除法
echo $((10 / 3)) # 3
# 浮点数除法
echo "scale=2; 10 / 3" | bc # 3.33
# 复杂计算
result=$(echo "scale=4; sqrt(2)" | bc)条件判断
if 语句
bash
#!/bin/bash
if [ 条件 ]; then
命令
fi
if [ 条件 ]; then
命令1
else
命令2
fi
if [ 条件1 ]; then
命令1
elif [ 条件2 ]; then
命令2
else
命令3
fi条件表达式
文件测试
| 表达式 | 说明 |
|---|---|
-e file | 文件存在 |
-f file | 是普通文件 |
-d file | 是目录 |
-r file | 可读 |
-w file | 可写 |
-x file | 可执行 |
-s file | 文件非空 |
-L file | 是符号链接 |
bash
if [ -f "/etc/passwd" ]; then
echo "文件存在"
fi
if [ -d "/home" ]; then
echo "目录存在"
fi字符串测试
| 表达式 | 说明 |
|---|---|
-z str | 字符串为空 |
-n str | 字符串非空 |
str1 = str2 | 字符串相等 |
str1 != str2 | 字符串不等 |
bash
name="Maxwell"
if [ -n "$name" ]; then
echo "名字非空"
fi
if [ "$name" = "Maxwell" ]; then
echo "名字匹配"
fi数值比较
| 表达式 | 说明 |
|---|---|
n1 -eq n2 | 等于 |
n1 -ne n2 | 不等于 |
n1 -gt n2 | 大于 |
n1 -ge n2 | 大于等于 |
n1 -lt n2 | 小于 |
n1 -le n2 | 小于等于 |
bash
age=25
if [ $age -ge 18 ]; then
echo "成年人"
fi逻辑运算
bash
# AND
if [ 条件1 ] && [ 条件2 ]; then
if [ 条件1 -a 条件2 ]; then
# OR
if [ 条件1 ] || [ 条件2 ]; then
if [ 条件1 -o 条件2 ]; then
# NOT
if [ ! 条件 ]; then[[ ]] 扩展测试
[[ ]] 是 Bash 扩展,功能更强:
bash
# 支持正则匹配
if [[ "$str" =~ ^[0-9]+$ ]]; then
echo "是数字"
fi
# 支持模式匹配
if [[ "$file" == *.txt ]]; then
echo "是文本文件"
fi
# 更安全的字符串比较
if [[ "$name" == "Maxwell" ]]; then
echo "匹配"
ficase 语句
bash
#!/bin/bash
case $1 in
start)
echo "启动服务"
;;
stop)
echo "停止服务"
;;
restart)
echo "重启服务"
;;
*)
echo "用法: $0 {start|stop|restart}"
exit 1
;;
esac循环
for 循环
bash
# 列表循环
for item in item1 item2 item3; do
echo $item
done
# 数组循环
arr=(one two three)
for item in ${arr[@]}; do
echo $item
done
# 文件循环
for file in *.txt; do
echo "处理: $file"
done
# 范围循环
for i in {1..5}; do
echo $i
done
# C 风格循环
for ((i=0; i<5; i++)); do
echo $i
done
# 命令输出循环
for user in $(cat /etc/passwd | cut -d: -f1); do
echo "用户: $user"
donewhile 循环
bash
#!/bin/bash
count=0
while [ $count -lt 5 ]; do
echo "Count: $count"
((count++))
done
# 读取文件
while IFS= read -r line; do
echo "行: $line"
done < file.txt
# 无限循环
while true; do
echo "运行中..."
sleep 1
doneuntil 循环
bash
count=0
until [ $count -ge 5 ]; do
echo "Count: $count"
((count++))
done循环控制
bash
# break - 退出循环
for i in {1..10}; do
if [ $i -eq 5 ]; then
break
fi
echo $i
done
# continue - 跳过本次
for i in {1..5}; do
if [ $i -eq 3 ]; then
continue
fi
echo $i
done函数
定义和调用
bash
#!/bin/bash
# 定义函数
function greet() {
echo "Hello, $1!"
}
# 或(POSIX 兼容)
greet() {
echo "Hello, $1!"
}
# 调用函数
greet "Maxwell"
greet "World"函数参数和返回值
bash
#!/bin/bash
add() {
local a=$1
local b=$2
local sum=$((a + b))
echo $sum # 通过 echo 返回值
}
# 获取返回值
result=$(add 3 5)
echo "结果: $result"
# 使用 return(只能返回 0-255)
check_file() {
if [ -f "$1" ]; then
return 0
else
return 1
fi
}
if check_file "/etc/passwd"; then
echo "文件存在"
fi局部变量
bash
#!/bin/bash
global_var="全局"
my_function() {
local local_var="局部"
global_var="在函数中修改"
echo "函数内: $local_var, $global_var"
}
my_function
echo "函数外: $global_var" # 在函数中修改
echo "函数外: $local_var" # 空(局部变量不可见)输入输出
读取用户输入
bash
#!/bin/bash
# 基本读取
echo -n "请输入名字: "
read name
echo "你好, $name"
# 带提示
read -p "请输入年龄: " age
# 隐藏输入(密码)
read -sp "请输入密码: " password
echo
# 设置超时
read -t 5 -p "5秒内输入: " answer
# 读取到数组
read -a arr -p "输入多个值: "
echo "第一个: ${arr[0]}"输出
bash
# echo
echo "普通输出"
echo -n "不换行"
echo -e "支持\t转义\n字符"
# printf(格式化输出)
printf "Name: %s, Age: %d\n" "Maxwell" 25
printf "%-10s %5d\n" "Item" 100实用示例
备份脚本
bash
#!/bin/bash
BACKUP_DIR="/backup"
SOURCE_DIR="/var/www"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/www_${DATE}.tar.gz"
# 创建备份目录
mkdir -p "$BACKUP_DIR"
# 创建备份
tar -czf "$BACKUP_FILE" "$SOURCE_DIR"
if [ $? -eq 0 ]; then
echo "备份成功: $BACKUP_FILE"
else
echo "备份失败"
exit 1
fi
# 删除 7 天前的备份
find "$BACKUP_DIR" -name "www_*.tar.gz" -mtime +7 -delete系统监控脚本
bash
#!/bin/bash
echo "=== 系统信息 ==="
echo "主机名: $(hostname)"
echo "系统: $(uname -s)"
echo "内核: $(uname -r)"
echo
echo "=== CPU 使用率 ==="
top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d% -f1
echo
echo "=== 内存使用 ==="
free -h | grep Mem
echo
echo "=== 磁盘使用 ==="
df -h | grep -v tmpfs小结
本章介绍了 Shell 脚本基础:
- 脚本结构:Shebang、注释、执行
- 变量:定义、使用、特殊变量
- 运算:算术运算、字符串操作
- 条件判断:if、case、测试表达式
- 循环:for、while、until
- 函数:定义、参数、返回值
- 输入输出:read、echo、printf
Shell 脚本是 Linux 自动化的基础,掌握它将大大提高你的工作效率。
上一章:SSH 远程连接
下一章:环境变量