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. 最佳实践

  1. 总是以 #!/bin/bash 开始脚本
  2. 使用 set -e 使脚本在出错时退出
  3. 使用 set -u 检查未设置变量
  4. 对变量使用引号,如 "$var"
  5. 使用 [[ ]] 代替 [ ] 进行条件测试
  6. 使用 $(command) 代替反引号
  7. 为脚本和函数添加注释
  8. 使用有意义的变量名
  9. 处理错误和异常情况
  10. 测试脚本在不同环境下的行为

12. 学习资源

希望这份详尽的 Shell 教程能帮助你掌握 Shell 脚本编程!









results matching ""

    No results matching ""