Shell 基础介绍
Shell 是用户与操作系统内核交互的接口,它既是一种命令语言,又是一种程序设计语言。常见的 Shell 包括:
- Bash (Bourne Again Shell) - Linux 默认
- Zsh - 功能更强大的替代品
- Ksh (Korn Shell)
- Csh/Tcsh (C Shell)
查看当前使用的 Shell:
echo $SHELL
查看系统可用的 Shell:
cat /etc/shells
2. Shell 脚本基础
2.1 创建第一个脚本
#!/bin/bash
# 这是一个注释
echo "Hello, World!"
保存为 hello.sh
,然后赋予执行权限:
chmod +x hello.sh
执行脚本:
./hello.sh
2.2 变量
定义变量:
name="John"
age=25
使用变量:
echo $name
echo ${age}岁
只读变量:
readonly PI=3.14159
删除变量:
unset name
2.3 特殊变量
$0
- 脚本名称$1-$9
- 脚本参数$#
- 参数个数$*
- 所有参数$@
- 所有参数(与$*有区别)$?
- 上一个命令的退出状态$$
- 当前进程ID
2.4 数组
定义数组:
fruits=("Apple" "Banana" "Orange")
访问数组元素:
echo ${fruits[0]} # Apple
echo ${fruits[@]} # 所有元素
echo ${#fruits[@]} # 数组长度
3. 字符串操作
3.1 基本操作
str="Hello World"
echo ${#str} # 字符串长度
echo ${str:0:5} # 子字符串
echo ${str:6} # 从第6个字符开始
3.2 字符串替换
str="Hello World World"
echo ${str/World/Shell} # 替换第一个
echo ${str//World/Shell} # 替换所有
3.3 字符串删除
path="/usr/local/bin"
echo ${path#/usr} # 删除最短匹配前缀
echo ${path##*/} # 删除最长匹配前缀
echo ${path%/bin} # 删除最短匹配后缀
echo ${path%%/bin} # 删除最长匹配后缀
4. 运算符
4.1 算术运算
a=10
b=3
# 使用 expr
echo `expr $a + $b`
# 使用 $(( ))
echo $((a + b))
# 使用 let
let "c = a + b"
echo $c
# 使用 bc 进行浮点运算
echo "scale=2; $a / $b" | bc
4.2 关系运算符
[ $a -eq $b ] # 等于
[ $a -ne $b ] # 不等于
[ $a -gt $b ] # 大于
[ $a -lt $b ] # 小于
[ $a -ge $b ] # 大于等于
[ $a -le $b ] # 小于等于
4.3 布尔和逻辑运算符
[ ! false ] # 非
[ $a -lt 20 -o $b -gt 100 ] # 或
[ $a -lt 20 -a $b -gt 100 ] # 与
4.4 字符串运算符
[ $str1 = $str2 ] # 相等
[ $str1 != $str2 ] # 不等
[ -z $str ] # 长度为0
[ -n $str ] # 长度不为0
[ $str ] # 不为空
4.5 文件测试运算符
[ -e file ] # 存在
[ -f file ] # 是普通文件
[ -d file ] # 是目录
[ -r file ] # 可读
[ -w file ] # 可写
[ -x file ] # 可执行
[ -s file ] # 大小不为0
5. 控制结构
5.1 条件语句
if [ condition ]; then
commands
elif [ condition ]; then
commands
else
commands
fi
示例:
if [ $a -gt $b ]; then
echo "$a 大于 $b"
elif [ $a -eq $b ]; then
echo "$a 等于 $b"
else
echo "$a 小于 $b"
fi
5.2 case 语句
case $变量 in
模式1)
commands
;;
模式2)
commands
;;
*)
default commands
;;
esac
示例:
read -p "输入一个数字 (1-3): " num
case $num in
1) echo "你输入了1" ;;
2) echo "你输入了2" ;;
3) echo "你输入了3" ;;
*) echo "输入不在1-3范围内" ;;
esac
5.3 for 循环
for 变量 in 列表
do
commands
done
示例:
for i in 1 2 3 4 5
do
echo "数字: $i"
done
# 使用序列
for i in {1..5}
do
echo "数字: $i"
done
# C风格for循环
for ((i=1; i<=5; i++))
do
echo "数字: $i"
done
5.4 while 循环
while [ condition ]
do
commands
done
示例:
count=1
while [ $count -le 5 ]
do
echo "计数: $count"
count=$((count+1))
done
5.5 until 循环
until [ condition ]
do
commands
done
示例:
count=1
until [ $count -gt 5 ]
do
echo "计数: $count"
count=$((count+1))
done
5.6 循环控制
break # 跳出循环
continue # 跳过本次循环
6. 函数
6.1 定义函数
function_name() {
commands
[return value]
}
或
function function_name {
commands
[return value]
}
6.2 函数示例
greet() {
echo "Hello, $1!"
}
greet "John" # 输出: Hello, John!
6.3 返回值
add() {
return $(($1 + $2))
}
add 3 5
echo "3 + 5 = $?" # $? 获取返回值
6.4 局部变量
func() {
local var="局部变量"
echo $var
}
7. 输入输出
7.1 读取输入
read -p "请输入您的名字: " name
echo "你好, $name!"
7.2 文件描述符
- 0: 标准输入
- 1: 标准输出
- 2: 标准错误
重定向:
command > file # 标准输出重定向到文件
command >> file # 标准输出追加到文件
command 2> file # 标准错误重定向到文件
command > file 2>&1 # 标准和错误都重定向到文件
command < file # 从文件读取输入
7.3 Here Document
cat << EOF
这是一个多行文本
第二行
第三行
EOF
8. 高级特性
8.1 命令替换
date=`date`
echo "当前日期: $date"
# 或使用 $()
files=$(ls)
echo "文件列表: $files"
8.2 算术扩展
a=5
b=7
echo $((a + b))
8.3 进程替换
diff <(ls dir1) <(ls dir2)
8.4 调试脚本
bash -x script.sh # 跟踪执行
bash -v script.sh # 显示原始命令
bash -n script.sh # 检查语法错误
在脚本中启用调试:
#!/bin/bash
set -x # 开启调试
# 脚本内容
set +x # 关闭调试
9. 实用技巧
9.1 获取脚本目录
SCRIPT_DIR=$(cd $(dirname "$0") && pwd)
9.2 检查命令是否存在
if ! command -v git &> /dev/null; then
echo "git 未安装"
exit 1
fi
9.3 颜色输出
RED='\033[0;31m'
NC='\033[0m' # No Color
echo -e "${RED}错误信息${NC}"
9.4 进度条
for i in {1..100}; do
printf "\r[%-100s] %d%%" $(printf "#%.0s" $(seq 1 $i)) $i
sleep 0.1
done
echo
10. 实战示例
10.1 备份脚本
#!/bin/bash
# 备份脚本
BACKUP_DIR="/backup"
SOURCE_DIR="/var/www"
DATE=$(date +%Y%m%d)
BACKUP_FILE="backup_$DATE.tar.gz"
if [ ! -d "$BACKUP_DIR" ]; then
mkdir -p "$BACKUP_DIR"
fi
tar -czf "$BACKUP_DIR/$BACKUP_FILE" "$SOURCE_DIR" 2>/dev/null
if [ $? -eq 0 ]; then
echo "备份成功: $BACKUP_DIR/$BACKUP_FILE"
else
echo "备份失败!"
exit 1
fi
10.2 系统监控脚本
#!/bin/bash
# 系统监控脚本
# 获取CPU使用率
cpu_usage=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')
# 获取内存使用率
mem_total=$(free -m | awk '/Mem:/ {print $2}')
mem_used=$(free -m | awk '/Mem:/ {print $3}')
mem_usage=$((mem_used * 100 / mem_total))
# 获取磁盘使用率
disk_usage=$(df -h / | awk '/\// {print $(NF-1)}')
echo "CPU 使用率: ${cpu_usage}%"
echo "内存使用率: ${mem_usage}%"
echo "根分区使用率: ${disk_usage}"
11. 最佳实践
- 总是以
#!/bin/bash
开始脚本 - 使用
set -e
使脚本在出错时退出 - 使用
set -u
检查未设置变量 - 对变量使用引号,如
"$var"
- 使用
[[ ]]
代替[ ]
进行条件测试 - 使用
$(command)
代替反引号 - 为脚本和函数添加注释
- 使用有意义的变量名
- 处理错误和异常情况
- 测试脚本在不同环境下的行为
12. 学习资源
- Bash 参考手册:
man bash
- Advanced Bash-Scripting Guide (ABS): https://tldp.org/LDP/abs/html/
- Bash Hackers Wiki: http://wiki.bash-hackers.org/
- Google Shell Style Guide: https://google.github.io/styleguide/shellguide.html
希望这份详尽的 Shell 教程能帮助你掌握 Shell 脚本编程!