📜 第19课:Shell脚本基础

阶段四:Shell脚本第1/6课

📚 课程目标

一、Shell概述

1.1 Shell是什么

Shell是用户与操作系统内核之间的接口程序,提供命令行交互和脚本编程能力。Linux默认Shell是Bash(Bourne Again Shell)。

1.2 常见Shell对比

Shell路径特点
sh/bin/shPOSIX标准Shell,通常指向dash
Bash/bin/bash最常用,Linux默认,功能丰富
Zsh/bin/zsh最强大,macOS默认,插件生态好
Dash/bin/dash轻量快速,Debian脚本默认
Fish/usr/bin/fish用户友好,自动补全,不POSIX兼容

1.3 Bash版本

$ bash --version | head -1
GNU bash, version 5.2.21(1)-release (x86_64-pc-linux-gnu)

二、第一个脚本

#!/bin/bash
# hello.sh - 第一个Shell脚本
echo "Hello, World!"
echo "当前用户: $(whoami)"
echo "当前目录: $(pwd)"
echo "系统时间: $(date)"
echo "内核版本: $(uname -r)"
echo "Shell版本: $BASH_VERSION"

2.1 执行方式

# 方式1:作为可执行程序(需要执行权限和shebang)
chmod +x hello.sh
./hello.sh

# 方式2:通过bash解释器执行(不需要执行权限)
bash hello.sh

# 方式3:source在当前Shell执行(影响当前环境)
source hello.sh
. hello.sh          # 等效写法

📋 三种执行方式对比

方式子Shell需执行权限影响当前Shell用途
./script常规执行
bash script调试/无权限时
source script加载函数/环境变量

2.2 Shebang详解

#!/bin/bash           # 使用bash执行
#!/bin/sh             # 使用POSIX sh执行
#!/usr/bin/env bash   # 更可移植,通过env查找bash
#!/usr/bin/env python3  # Python脚本

三、变量

3.1 赋值与使用

# 赋值(等号两边不能有空格!)
NAME="Linux"
VERSION=7
PATH_DIR="/var/log"

# 使用变量
echo $NAME                    # Linux
echo "$NAME version $VERSION" # Linux version 7
echo "${NAME}_VERSION"        # Linux_VERSION(花括号消除歧义)

# 只读变量
readonly PI=3.14159
# PI=3  # 报错:readonly variable

# 删除变量
unset NAME

3.2 引号差异

NAME="World"

# 双引号:变量展开,允许转义
echo "Hello, $NAME"        # Hello, World
echo "Hello, \$NAME"       # Hello, $NAME(转义$)
echo "Path: $PATH"         # 变量展开

# 单引号:原样输出,不做任何展开
echo 'Hello, $NAME'        # Hello, $NAME
echo 'Path: $PATH'         # Path: $PATH

# 反引号/$():命令替换
echo "Today: $(date +%F)"  # Today: 2024-01-15(推荐)
echo "Files: `ls | wc -l`" # 旧语法,不推荐

3.3 特殊变量

变量含义示例
$0脚本文件名./script.sh
$1-$9位置参数第一个到第九个参数
${10}第10个参数需要花括号
$#参数个数3
$@所有参数(独立字符串)"a" "b" "c"
$*所有参数(单个字符串)"a b c"
$?上一命令退出码0(成功)/1(失败)
$$当前脚本PID12345
$!最近后台进程PID12346

四、输入输出

4.1 echo与printf

# echo
echo "Hello"              # 输出后换行
echo -n "Hello"           # 不换行
echo -e "Line1\nLine2"    # 解释转义字符

# printf(更灵活,推荐用于格式化输出)
printf "Name: %s\n" "Linux"
printf "Number: %d\n" 42
printf "Float: %.2f\n" 3.14159
printf "%-10s %5d\n" "Item" 100    # 左对齐10字符,右对齐5数字

4.2 read读取输入

# 基本读取
echo -n "请输入姓名: "
read NAME
echo "你好, $NAME!"

# 带提示的读取(一行写法)
read -p "请输入年龄: " AGE

# 密码输入(不回显)
read -s -p "密码: " PASSWORD

# 限制时间
read -t 10 -p "10秒内输入: " INPUT

# 读取多个值
read -p "姓名 年龄: " NAME AGE

4.3 重定向

# 标准输出重定向
command > file          # 覆盖写入
command >> file         # 追加写入

# 标准错误重定向
command 2> error.log    # 错误到文件
command 2>> error.log   # 错误追加

# 合并输出
command > all.log 2>&1  # 标准输出和错误都到文件
command &> all.log      # 等效简写(Bash 4+)

# 丢弃输出
command > /dev/null 2>&1

# 输入重定向
command < input.txt

# Here Document
cat << EOF
这是多行文本
变量展开: $NAME
EOF

# Here String
grep "pattern" <<< "search in this string"

五、算术运算

# 算术展开 $(( ))
echo $((1 + 2))        # 3
echo $((10 - 3))       # 7
echo $((4 * 5))        # 20
echo $((10 / 3))       # 3 (整数除法)
echo $((10 % 3))       # 1 (取余)
echo $((2 ** 10))      # 1024 (幂运算)

# let命令
let x=1+2; echo $x      # 3
let x++; echo $x         # 4 (自增)
let x+=5; echo $x        # 9 (加赋值)

# expr命令(不推荐,速度慢)
expr 1 + 2              # 3

# bc浮点运算
echo "scale=2; 10/3" | bc    # 3.33
echo "sqrt(2)" | bc -l       # 1.41421356...

六、环境变量

# 常用环境变量
echo $HOME        # /root (家目录)
echo $USER        # root (当前用户)
echo $PATH        # 命令搜索路径
echo $PWD         # 当前目录
echo $SHELL       # /bin/bash
echo $HOSTNAME    # 主机名
echo $LANG        # 语言设置
echo $RANDOM      # 随机数(0-32767)

# 设置环境变量
export MY_VAR="hello"         # 当前会话
echo 'export MY_VAR="hello"' >> ~/.bashrc  # 永久生效
source ~/.bashrc              # 立即生效

七、脚本调试

# Bash调试选项
bash -n script.sh       # 仅检查语法(不执行)
bash -x script.sh       # 执行追踪(打印每条命令及其参数)
bash -v script.sh       # 详细模式(打印读入的每一行)

# 脚本内启用/关闭调试
set -x    # 开启追踪
# ... 需要调试的代码 ...
set +x    # 关闭追踪

# 安全模式(推荐所有脚本使用)
set -euo pipefail
# -e: 命令失败时立即退出
# -u: 使用未定义变量时报错
# -o pipefail: 管道中任一命令失败则整个管道失败

# 错误捕获
trap 'echo "Error at line $LINENO"; exit 1' ERR

八、脚本模板

#!/bin/bash
# 描述: Shell脚本模板
# 作者: admin
# 日期: $(date +%Y-%m-%d)
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
LOG_FILE="/tmp/$(basename "$0" .sh).log"

log() { echo "$(date '+%Y-%m-%d %H:%M:%S') $*" | tee -a "$LOG_FILE"; }
die() { log "FATAL: $*" >&2; exit 1; }

usage() {
    echo "Usage: $(basename "$0") [OPTIONS]"
    echo "  -h    显示帮助"
    echo "  -v    详细输出"
    echo "  -f FILE  指定文件"
}

CONFIG_FILE=""
while getopts "hvf:" opt; do
    case $opt in
        h) usage; exit 0 ;;
        v) set -x ;;
        f) CONFIG_FILE="$OPTARG" ;;
        *) usage; exit 1 ;;
    esac
done

main() {
    log "脚本开始执行"
    # 在此添加业务逻辑
    log "脚本执行完成"
}

main "$@"

九、练习

📝 编写系统信息脚本

#!/bin/bash
# sysinfo.sh
echo "===== 系统信息报告 ====="
echo "主机名: $(hostname)"
echo "内核: $(uname -r)"
echo "架构: $(uname -m)"
echo "CPU: $(nproc)核"
echo "内存: $(free -h | grep Mem | awk '{print $2}')"
echo "磁盘使用:"
df -h | grep -v tmpfs | grep -v udev
echo "IP: $(hostname -I | awk '{print $1}')"
echo "运行时间: $(uptime -p)"
echo "登录用户: $(who | wc -l)"
🏆

成就解锁:Shell入门者

✅ 理解Shell种类与特性

✅ 掌握脚本基本结构

✅ 学会变量、引号、重定向

✅ 掌握特殊变量与参数

✅ 学会脚本调试技巧

十、Shell脚本最佳实践

📋 脚本编写规范

  1. 总是使用set -euo pipefail:防止静默失败
  2. 引用所有变量:"$var"而非$var
  3. 使用[[ ]]替代[ ]:更安全,支持正则
  4. 函数化:将逻辑封装为函数,便于测试和复用
  5. 记录日志:所有操作都应有日志
  6. 参数校验:脚本开头检查必需参数
  7. 提供帮助信息:-h选项显示用法
  8. 清理临时文件:trap EXIT确保清理
#!/bin/bash
# 最佳实践模板
set -euo pipefail

# 参数校验
if [[ $# -lt 1 ]]; then
    echo "用法: $0 <必需参数> [可选参数]" >&2
    exit 1
fi

# 清理
TMPDIR=$(mktemp -d)
trap 'rm -rf "$TMPDIR"' EXIT

# 日志
log() { echo "[$(date +%T)] $*"; }
err() { log "ERROR: $*" >&2; exit 1; }

# 主逻辑
main() {
    local input="$1"
    log "处理: $input"
    # ...
    log "完成"
}

main "$@"

十一、Shell脚本性能

# 避免不必要的子Shell
# 慢: for f in $(ls); do ...
# 快: for f in *; do ...

# 使用内置命令而非外部命令
# 慢: expr 1 + 2
# 快: echo $((1 + 2))

# 慢: cat file | grep pattern
# 快: grep pattern file

# 使用 Bash 内置字符串操作
# 慢: echo "$var" | sed 's/old/new/'
# 快: echo "${var/old/new}"

# 慢: basename /path/to/file
# 快: echo "${path##*/}"

# 慢: dirname /path/to/file
# 快: echo "${path%/*}"

十二、Shell脚本安全

📋 安全检查清单

附录:Shell脚本学习资源

推荐书籍

书名作者重点
Linux命令行与Shell脚本编程大全BlumShell脚本全面覆盖
UNIX/Linux系统管理技术手册Nemeth系统管理圣经
Ansible: Up and RunningLintnerAnsible实战
鸟哥的Linux私房菜鸟哥中文经典入门

在线资源

认证路径

认证机构级别
LFCSLinux Foundation基础系统管理
LFCELinux Foundation高级系统工程师
RHCSARed HatRed Hat管理员
RHCERed HatRed Hat工程师
CKA/CKADCNCFKubernetes管理员/开发者

实践环境

常用速查表

# 文本处理速查
grep -E 'pattern' file     # 扩展正则搜索
sed -i 's/old/new/g' file  # 替换
awk '{print $1}' file     # 提取列
sort | uniq -c | sort -rn   # 频次统计
cut -d: -f1 file            # 切列
tr 'A-Z' 'a-z'             # 转小写

# 系统管理速查
systemctl status/start/stop/restart service
journalctl -u service -f    # 跟踪日志
df -h / du -sh *            # 磁盘使用
ps aux --sort=-%mem         # 内存排序
ss -tlnp                    # 监听端口
iptables -L -n              # 防火墙规则
crontab -e                  # 编辑定时任务
useradd -m -s /bin/bash user # 创建用户

# 网络诊断速查
ip addr / ip route          # 网络配置
ping / traceroute           # 连通测试
dig / nslookup              # DNS查询
curl -I url                 # HTTP头检查
nc -zv host port            # 端口测试
tcpdump -i eth0 port 80     # 抓包