Shell 脚本就像是一个永不疲倦、从不抱怨的私人助理,以机器人般的精确度执行你的命令。它是一种将命令行指令串联起来,创建强大自动化工作流程的艺术。

Shell 脚本如何帮助你?

  • 自动化重复性任务(因为生活太短暂,不能总是用 ctrl+C 和 ctrl+V)
  • 像老板一样管理系统进程
  • 创建可重复的操作(这样未来的你就不会诅咒过去的你)
  • 展示你的 Linux 技能,给同事留下深刻印象

在我们开始之前,先明确一点:我们这里讨论的是 Bash。当然,还有其他 shell,比如 Zsh、Fish 或者经典的 Sh,但 Bash 是 Linux 世界中大家都喜欢的那个酷小子。

与你的 Shell 脚本初次约会

让我们从经典的 "Hello, World!" 开始,因为这是传统:

#!/bin/bash
echo "Hello, World! 我是一个 shell 脚本,很高兴见到你!"

将其保存为 hello_world.sh,然后我们来解析一下:

  • #!/bin/bash:这被称为 shebang。就像是在告诉计算机,“嘿,用 Bash 来运行这个,好吗!”
  • echo:这个命令就像是在对着虚空大喊,只不过这个虚空是你的终端。

现在,让我们使其可执行并运行它:

chmod +x hello_world.sh
./hello_world.sh

砰!你现在正式成为一个 shell 脚本编写者了。把这个写进你的简历吧!😄

变量:Shell 生活的调味品

Shell 脚本中的变量就像是你数字物品的容器。让我们来玩一下:

#!/bin/bash

# 给变量赋值
greeting="Hello, earthling!"

# 使用变量
echo $greeting

# 从用户获取输入
read -p "你叫什么名字?" name
echo "很高兴见到你, $name!"

专业提示:使用变量时,用大括号包裹它们,如 ${variable},以避免歧义。未来的你会感谢现在的你。

控制结构:让 Shell 听你的话

现在,让我们为脚本添加一些逻辑。我们将从 if-then-else 结构开始,这是决策的基础:

#!/bin/bash

read -p "输入一个数字: " num

if [ $num -gt 10 ]; then
    echo "这是个大数字!"
elif [ $num -eq 10 ]; then
    echo "你找到了甜蜜点!"
else
    echo "想得更大些!"
fi

这里有一个循环,让你感觉自己在 黑客帝国 中:

#!/bin/bash

for i in {1..5}
do
    echo "迭代 $i"
    sleep 1  # 暂停以增加戏剧效果
done

echo "循环完成。思维 = 震撼。"

文件操作:因为数据不会自己移动

让我们创建一个脚本来备份文件并添加时间戳:

#!/bin/bash

# 检查是否提供了文件名
if [ $# -eq 0 ]; then
    echo "用法: $0 "
    exit 1
fi

filename=$1
timestamp=$(date +"%Y%m%d_%H%M%S")
backup_file="${filename}_${timestamp}.bak"

# 检查文件是否存在
if [ ! -f "$filename" ]; then
    echo "错误: 文件 '$filename' 未找到。"
    exit 1
fi

# 创建备份
cp "$filename" "$backup_file"

if [ $? -eq 0 ]; then
    echo "备份成功创建: $backup_file"
else
    echo "错误: 备份失败。"
fi

这个脚本引入了一些新概念:

  • $#:传递给脚本的参数数量
  • $1:传递给脚本的第一个参数
  • $(command):命令替换 - 运行一个命令并返回输出
  • $?:最后一个命令的退出状态(0 表示成功)

错误处理:因为错误总会发生

让我们用一些错误处理来升级我们的脚本:

#!/bin/bash

set -e  # 如果命令以非零状态退出,则立即退出
set -u  # 将未设置的变量视为错误

log_error() {
    echo "错误: $1" >&2
}

backup_file() {
    local filename=$1
    local backup_dir="/tmp/backups"

    # 如果备份目录不存在,则创建
    mkdir -p "$backup_dir" || { log_error "创建备份目录失败"; return 1; }

    # 将文件复制到备份目录
    cp "$filename" "$backup_dir" || { log_error "复制文件失败"; return 1; }

    echo "备份 $filename 已创建在 $backup_dir"
}

# 主脚本执行
main() {
    if [ $# -eq 0 ]; then
        log_error "用法: $0 "
        exit 1
    fi

    backup_file "$1"
}

main "$@"

这个脚本引入了:

  • set -eset -u 用于更严格的错误检查
  • 用于错误日志记录的函数
  • 用于组织脚本逻辑的主函数

高级技巧:提升你的 Shell 技能

现在我们已经覆盖了基础知识,让我们看看一些更高级的技巧:

1. 使用数组

#!/bin/bash

# 声明一个数组
fruits=("apple" "banana" "cherry")

# 遍历数组
for fruit in "${fruits[@]}"
do
    echo "我喜欢 $fruit"
done

# 向数组添加一个元素
fruits+=("date")

# 打印整个数组
echo "所有水果: ${fruits[*]}"

2. 带返回值的函数

#!/bin/bash

is_even() {
    if [ $(($1 % 2)) -eq 0 ]; then
        return 0  # 真(在 bash 中,0 为真)
    else
        return 1  # 假
    fi
}

number=42
if is_even $number; then
    echo "$number 是偶数"
else
    echo "$number 是奇数"
fi

3. 从文件读取

#!/bin/bash

filename="sample.txt"

while IFS= read -r line
do
    echo "行: $line"
done < "$filename"

最佳实践:不要自找麻烦

  • 始终在脚本开头使用 set -eset -u
  • 引用你的变量:"$variable" 而不是 $variable
  • 在函数中使用 local 变量以避免污染全局命名空间
  • 注释你的代码(未来的你会感谢现在的你)
  • 使用有意义的变量和函数名
  • 彻底测试你的脚本,尤其是边缘情况

常见陷阱:从他人的错误中学习

  • 忘记使你的脚本可执行(chmod +x script.sh
  • test 括号中使用 == 而不是 = 进行字符串比较
  • 不处理文件名中的空格(使用引号!)
  • 假设命令成功而不检查其退出状态

总结:Shell 及其未来

恭喜你!你已经迈出了进入强大 Shell 脚本世界的第一步。拥有这些技能,你已经在自动化任务、管理系统以及成为命令行高手的路上了。

记住,Shell 脚本只是开始。随着你越来越熟练,你可能想要探索:

  • 使用 awksed 进行更高级的文本处理
  • 使用 cron 调度你的脚本
  • 使用 Git 进行脚本版本控制
  • 将你的脚本与其他工具和服务集成

继续实验,继续学习,最重要的是,继续编写脚本!命令行是你的珍宝,而你有工具来打开它。

“一个好的管理员和一个伟大的管理员之间的区别大约是 40 个 shell 脚本。” - 未知

现在去吧,自动化一切!🚀