课堂笔记
Shell 脚本最朴素的形态就是把多个命令串联在一起执行。在命令行 中,我们可以用分号将多个命令放在同一行,shell 会按顺序依次执行它们。这种方式虽然简单,但已经体现了脚本的核心思想——将一系列操作自动化。比如 date; who 会先显示当前时间,再显示登录用户信息,两个命令互不干扰,依次输出结果。
一.创建 Shell 脚本文件
当命令数量增多或逻辑变复杂时,把命令写入文件才是更可持续的方式。创建脚本文件时有几个关键点需要留意:
1.指定解释器:脚本第一行必须是 #!/bin/bash,这告诉系统使用哪个 shell 来执行该脚本。其中 #! 是特殊标记,普通行以 # 开头的则是注释,唯独第一行例外。
2.运行方式:脚本创建后不能直接运行,因为 shell 只在 PATH 环境变量指定的目录中查找命令。有两种方式可以执行脚本:
将脚本所在目录加入 PATH
使用绝对路径或相对路径(如 ./script.sh)显式指定
3.执行权限:如果遇到 Permission denied,需要用 chmod u+x script.sh 为文件所有者添加执行权限。
二.显示消息 —— echo 命令
echo 是在脚本中与用户交互最基本的手段,用于输出提示信息或运行状态。
使用时有几个小细节值得注意:
文本字符串可以不用引号括起来,但如果文本中包含引号,则需用另一种引号将整个字符串包住。
默认情况下 echo 会在输出末尾自动换行,若想让后续内容接在同一行,可以使用 -n 选项。
这样用户就能清楚脚本正在执行什么操作,而不是面对一堆黑屏等待。
三、使用变量
变量是脚本中临时存储数据的容器,分为环境变量和用户自定义变量两类。
3.1 环境变量
系统预定义的环境变量(如 $USER、$HOME、$UID)可以直接在脚本中通过美元符引用。这里有一个常见的陷阱:当字符串中出现 $ 符号时,shell 会误以为是在引用变量。例如想输出 “The cost is $15”,脚本会尝试显示一个名为 $1 的变量再跟一个 5。解决方法是使用反斜线对美元符进行转义(\$15)。
3.2 用户自定义变量
用户可以自己定义变量来存储临时数据。变量名由字母、数字、下划线组成,长度不超过 20 个字符,且区分大小写。赋值时等号两边不能有空格(如 guest="Tom")。引用时同样在变量名前加 $。
值得一提的是,变量的值是可以随时修改的,甚至可以用一个变量去赋值另一个变量,这为脚本中的数据处理提供了很大的灵活性。
3.3 命令替换
这是 shell 脚本最有用的特性之一 —— 将命令的输出结果赋给变量。有两种语法形式:反引号(`)和 $() 格式。例如用 today=$(date +%y%m%d) 获取当前日期并拼接到文件名中,可以生成带时间戳的日志文件,避免文件被覆盖。
四、输入输出重定向
重定向的核心是改变数据的流向,让命令从文件读取数据或将输出写入文件。
4.1 输出重定向
>:将命令输出写入文件,若文件已存在则覆盖。
>>:将输出追加到文件末尾,保留原有内容。
这在记录日志或保存命令结果时非常实用。
4.2 输入重定向
<:将文件内容作为命令的输入。例如 wc < filename 会统计文件的行数、词数和字节数。
<<(内联输入重定向):直接在命令行中指定输入数据,而不是从文件读取。使用时需指定一个文本标记来标识数据的开始和结束,标记可以任意字符串,但首尾必须一致。
五、管道
管道(|)解决了将一个命令的输出直接传给另一个命令作为输入的问题。相比于先用重定向保存到文件再用另一个命令读取,管道更加简洁高效,且无需中间文件。
最典型的应用场景是配合 more 分页查看大量输出,或配合 grep 筛选特定内容。管道可以串联任意多个命令,形成一个处理链条,让数据在命令间流动。
六、数学运算
Bash 本身对数学运算的支持有限,主要有三种方式:
6.1 expr 命令
expr 是一个用于执行算术和字符串操作的老牌命令。但使用时有几个不便之处:操作符和操作数之间必须用空格隔开,且部分特殊字符(如 *)需要转义,否则会被 shell 误解。
6.2 方括号 —— 推荐方式
$[operation] 语法更加直观和易用,例如 $[1 + 5] 或 $[$var1 * 2]。这种方式清晰明了,是日常脚本中最常用的整数运算方法。
但这两种方式都只支持整数运算,遇到除法时会直接截断 小数部分。
6.3 bc 计算器 —— 浮点运算
当需要处理浮点数时,就必须借助 bc 这一强大的计算器工具。bc 实际上是一种完整的编程语言,支持变量、数组、函数甚至条件语句。
在脚本中使用 bc 的典型格式是 variable=$(echo "options; expression" | bc),其中 options 可以设置 scale 变量来控制小数位数(默认为 0)。对于较复杂的表达式,还可以使用 << 内联输入将多行表达式传递给 bc。
需要留意的是,bc 中定义的变量在退出后会消失,因此需要在同一个 bc 会话中完成所有相关计算。
七、退出脚本 —— 退出状态码
每个命令执行完毕后都会返回一个 0~255 的整数值作为退出状态码,用于告知 shell 执行结果。其中 0 表示成功,其他值表示不同类型的错误。
特殊变量 $? 保存着上一个命令的退出状态码。
脚本默认以最后一个命令的退出状态码作为自己的退出状态。
我们可以用 exit 命令在脚本中主动指定退出码,例如 exit 5。
常见的退出状态码含义包括:1 表示一般性未知错误,126 表示命令不可执行,127 表示命令未找到,130 表示被 Ctrl+C 终止等。合理地设置退出状态码有助于调用脚本的上层程序判断执行结果。
八、总结
本次课程构建了 Shell 脚本编程的基本框架。从最基础的分号串联命令,到编写独立的脚本文件;从变量的定义与引用,到输入输出重定向和管道;再到数学运算和退出状态码的管理 —— 这些知识点共同构成了编写实用 Shell 脚本的基石。
理解这些概念后,我们已经能够写出具有一定功能的自动化脚本,例如带提示信息的用户管理脚本、带时间戳的日志备份脚本等。后续的学习将在这些基础上进一步深入流程控制、函数定义等高级话题。