| title | 命令行与 Shell 基础 |
|---|---|
| author | 晨星 |
| modified | 2026-10-13 |
| status | unread |
| direction | technical-development |
电影里的黑客常常在一个黑色窗口中敲下指令,电脑随即开始工作。这个窗口是什么?里面的文字为什么能让电脑执行操作?
我们平时用鼠标点击文件夹、拖动文件,也可以用文字告诉电脑做同样的事。承载这些文字的窗口通常是终端,理解并组织指令的程序叫 Shell。这篇教程从两者的区别开始,逐步介绍目录、文件和文本处理,最后把命令组合成自动运行的脚本。
本文是工具入门的起点,不要求编程、Git 或 Linux 使用经验。开始前,你只需要会在电脑上创建文件夹、用编辑器保存纯文本文件,并知道自己使用的是 Windows、macOS 还是 Linux。打开终端和准备 Bash 的方法会在第 1 节说明。
建议按这个顺序学习:本文 → Git 基础与 GitHub 协作 → 静态网站部署。先学会在目录中运行命令,再用 Git 保存和协作修改文件,最后把网站发布到网上。每篇教程仍使用自己的示例目录,无需沿用上一篇的文件。
这三篇属于 技术研发方向 的基础工具课程。熟悉命令、路径和日志处理后,你会更容易读懂 Docker 入门 中的容器命令,以及 服务器运维基础 中的日志和故障排查;这两篇可以在需要时继续阅读。
第 1–3 节介绍环境和基础命令,第 4–5 节解释如何组织数据与命令,第 6 节介绍查帮助和读报错,第 7 节展示脚本。代码和示例数据都写在正文中,可以直接阅读,也可以在自己的示例目录逐行尝试。
代码块中 # 后面是 Bash 注释,用来解释命令,运行时会被忽略。代码块下标为“输出”的内容是电脑显示的结果,不要再复制进终端。命令使用英文符号,尤其注意直引号 "、单引号 ' 与中文标点的区别。
遇到疑惑时,可以与大模型、内训老师或中管沟通。提问时附上当前 Shell、完整命令和报错,比只说“运行不了”更容易获得帮助;大模型给出的命令也要先看懂作用再运行。
图形界面(GUI)让你通过窗口、图标和按钮操作电脑,例如在文件管理器中双击一个文件夹。命令行界面(CLI)让你输入文字完成操作,例如输入 ls 查看目录内容。两者是与程序交互的不同方式。
命令行的价值在于操作可以准确描述、重复执行和组合。只处理一两个文件时鼠标很方便;要在许多文本中寻找某个词,或每天重复同一组操作时,一条命令或一个脚本往往更容易复用。
“命令行”不是某个固定软件的名字。许多程序都提供命令行界面,你输入的命令可能调用 Shell 自带的功能,也可能启动另一个程序。
终端负责接收键盘输入、显示程序输出。macOS 的“终端”、Windows Terminal 都是终端应用。背景是否黑色、字体是什么颜色,并不决定它能执行哪些命令。
可以把终端理解成接待窗口:你在这里输入文字,也在这里看到结果;实际读懂指令和完成工作的程序运行在窗口里面。一个终端可以开多个标签页,不同标签页还可以运行不同的 Shell。
因此,打开 Windows Terminal 后,里面可能是 PowerShell、命令提示符,也可能是 WSL 中的 Bash。窗口名字相同,不代表里面使用同一种语法。 Windows Terminal 官方介绍
Shell 是命令解释器。你按 Enter 后,它会分析输入:要运行什么程序,哪些文字是选项和参数,是否要读取文件或连接其他命令,再安排程序执行。
例如输入 ls notes 时,Shell 把 ls 识别为命令,把 notes 作为参数交给它;ls 再列出这个目录里的内容。输入带有 | 或 > 的命令时,Shell 还会安排程序之间的数据传递或输出文件。
Shell 也能运行脚本。脚本就是把操作写进文本文件,并加入变量、条件、循环,让电脑按规则执行。Bash、Zsh、PowerShell 都属于 Shell,但各自语法并不完全相同。
键盘输入 → 终端接收 → Shell 分析并运行命令 → 程序产生结果 → 终端显示
操作系统负责管理文件、进程和设备,是这些程序运行的基础。Shell 不是操作系统;使用 Bash 也不意味着电脑已经变成 Linux。
CMD(命令提示符) 是 Windows 传统的命令解释器,程序通常是 cmd.exe。它能运行 dir、copy 等命令和批处理文件,命令及脚本规则与 Bash 不同。
PowerShell是功能丰富的 Shell 和自动化工具,适合 Windows 管理,也有跨平台版本。它通常使用 Get-ChildItem 等命令,管道经常传递带属性的对象;本文的 Bash 管道主要处理文本。PowerShell 提供一些别名,因而输入 ls 也可能有输出,但这不保证 Bash 的 ls -a、变量写法或脚本能照搬。PowerShell 官方介绍
Bash常见于 Linux,也能在 macOS 和 Windows 上使用。本文选择 Bash,是为了让不同系统的同学使用同一套示例,并为以后阅读服务器命令和自动化脚本打下基础。PowerShell 完全可以完成文件操作、搜索和自动化,只是需要使用它自己的命令与语法。
Windows 上有两种常见的 Bash 环境:
- Git Bash:随 Git for Windows 安装,提供 Bash 和许多常见命令,直接操作 Windows 文件。首次学习选它比较省事。
- WSL:Windows Subsystem for Linux,可以在 Windows 中运行 Linux 发行版环境。已有 WSL 的同学可使用其中的 Bash;它涉及另一套环境和路径,不必为了阅读本文临时安装。
如果只打开了 PowerShell 或 CMD,请先打开 Git Bash,或进入已有的 WSL 环境;本文代码不会因为窗口颜色相同就自动兼容这些 Shell。
macOS 的默认 Shell 通常是 Zsh,Bash 是另一种 Shell。它们都能运行许多常见命令,pwd、cd、ls 等操作很相似;但通配符、数组、配置文件及一些交互行为有差异,脚本不能仅凭“看起来差不多”就换解释器运行。
在 macOS 的“终端”输入 bash,按 Enter,即可临时进入 Bash。输入 exit 会退出它,回到原来的 Shell。这不会修改系统默认 Shell,无需为了跟读教程更改终端设置。Apple 的 Shell 说明
| 你的电脑 | 如何开始 |
|---|---|
| Windows | 安装 Git for Windows,在开始菜单打开 Git Bash;已有 WSL 也可使用其中的 Bash |
| macOS | 打开“终端”,输入 bash,按 Enter |
| Linux | 打开终端;如果当前使用其他 Shell,输入 bash,按 Enter |
在已经进入 Bash 的窗口中执行:
bash --version # 显示可用 Bash 的版本;本身不会切换当前 Shell
echo hello # 在终端输出 hello
date # 输出电脑当前的日期和时间第一条显示版本信息,第二条输出 hello,第三条随系统时间变化。本文示例兼容 macOS 常见的 Bash 3.2,无需追求与老师完全相同的版本。
输入位置附近的文字叫提示符,例如 user@computer:~$ 或 bash-3.2$。它可能显示用户名和目录;示例里省略提示符,你只需输入命令本身。
按 Enter 后,程序通常开始运行;再次出现提示符,表示可以输入下一条。如果迟迟没有提示符,可能是程序仍在工作;Ctrl+C 可以请求停止前台程序。若出现 > 续行提示,常见原因是引号没闭合,Shell 正在等你继续输入,也可以先按 Ctrl+C 取消。
下表用于查阅,后面会分别解释。文件名、目录名是示例,执行时确认对象真实存在。
| 命令示例 | 作用 |
|---|---|
pwd |
显示当前目录的完整路径 |
ls、ls -a |
列出目录内容;-a 包含隐藏文件 |
cd notes、cd .. |
进入 notes;返回上一级目录 |
mkdir notes |
新建目录 |
touch note.txt |
新建空文件,或更新已有文件的时间戳 |
cat note.txt |
显示文本内容 |
less note.txt |
分页阅读文本,按 q 退出 |
cp note.txt copy.txt |
复制文件,来源在前,目标在后 |
mv copy.txt draft.txt |
移动文件,或给文件改名 |
rm -i draft.txt |
询问后删除指定文件 |
grep '关键词' note.txt |
显示包含关键词的行 |
wc -l note.txt |
统计文本行数 |
echo hello |
输出一段简单文字 |
exit |
退出当前 Shell |
小技巧:Tab 可以补全命令、目录或文件名;上下箭头可以找之前输入过的命令。执行前仍要确认目标,尤其是修改或删除文件时。
每次 Shell 会话都有一个当前工作目录。很多命令没有写完整路径时,就从这里找文件。因此,同一句 cat note.txt 在两个目录运行,可能读到不同文件,也可能报不存在。
当前目录不一定等于编辑器正在显示的文件夹,也不会自动跟随文件管理器改变。先确认位置,再操作文件,可以减少许多莫名其妙的错误。
pwd # print working directory,显示当前位置
ls # list,查看这里有哪些文件和目录
ls -a # 包括以点开头的隐藏文件
ls -l # 显示大小、时间、权限等详细信息命令常写成 命令名 选项 参数。例如 ls -a notes 中,ls 是命令,-a 是改变行为的选项,notes 是查看对象。选项由具体命令定义,不能认为所有命令的 -a 都表示同一件事。
绝对路径从文件系统根目录开始,完整描述一个位置;相对路径从当前目录开始描述位置。例如,当前在 /Users/name/shell-demo,相对路径 notes/todo.txt 指向 /Users/name/shell-demo/notes/todo.txt。
| 写法 | 含义 |
|---|---|
/ |
Unix 风格路径的根目录 |
~ |
当前用户的主目录 |
. |
当前目录 |
.. |
上一级目录 |
/Users/name/shell-demo |
macOS 绝对路径示例;name 换成真实用户名 |
notes/todo.txt |
当前目录下 notes 里面的 todo.txt |
Windows Git Bash 中,C:\Users\name 常写成 /c/Users/name;WSL 访问 Windows 的 C 盘时常用 /mnt/c/Users/name。这是不同环境的表示,不能原样互换。
下面创建 shell-demo,让示例文件有明确位置。已有同名重要目录时换个名字;后面以这个目录为例,不需要下载素材。
cd ~ # 回到自己的主目录
mkdir -p shell-demo # -p 允许目录已经存在
cd shell-demo # 进入目录
mkdir -p notes logs scripts # 空格分开三个参数,分别创建三个目录
pwd # 输出应以 /shell-demo 结尾
ls # 应看到 notes、logs、scriptscd notes # 进入子目录
pwd # 路径末尾变为 /shell-demo/notes
cd .. # 返回 shell-democd 是 change directory 的缩写,不带参数时回到主目录。cd / 进入文件系统根目录,二者不是同一个位置。cd notes 报不存在时,先看 pwd、ls,确认 notes 是否在当前目录下。
mkdir -p notes logs scripts 一次创建三个目录,是因为 Shell 把空格分隔的文字当成不同参数。想创建一个名为 my notes 的目录,就要告诉 Shell:空格属于名字,而不是分隔符。
mkdir -p "my notes" # 双引号把 my notes 包成一个参数
cd "my notes" # 进入含空格的目录
pwd
cd .. # 返回 shell-demo省略引号,mkdir my notes 会尝试创建 my 和 notes 两个目录;cd my notes 则给 cd 传入两个参数,通常报错。引号不会成为文件名的一部分,只影响 Shell 怎样理解输入。
这里写 'my notes' 也能保留空格。单双引号在变量展开时有区别,第 5 节会说明。英文直引号成对使用,中文 “my notes” 不能替代 Shell 引号。
"~/shell-demo" 中的波浪号不会像未引用时那样展开为主目录。需要把主目录路径放进引号时,使用 "$HOME/shell-demo";HOME 是保存主目录路径的变量。
touch 创建空文件,不会写入正文;已有文件再 touch,主要是更新时间戳。可以用编辑器写文字,也可以把命令输出保存到文件。下面的 > 是一种保存方式,第 4 节会解释。
在 ~/shell-demo 中:
touch notes/todo.txt # 创建空文本
printf '今天了解命令行\n' > notes/todo.txt # 写入一行,覆盖原内容
cat notes/todo.txt # 显示正文输出:
今天了解命令行
printf 按指定格式输出文字,\n 表示换行。cat 读取文件并把内容写到标准输出;这里把它作为查看短文本的工具。
长文件可用 less notes/todo.txt 分页看:空格翻页,q 退出。head -n 5 文件名 看前五行,tail -n 5 文件名 看后五行。PDF、图片等二进制文件用相应查看器,直接 cat 不会得到可读正文。
cp 是 copy,保留原文件并产生副本;mv 是 move,可以移动文件,也可以在同一目录内改名。二者参数顺序都是“来源在前,目标在后”。
cp notes/todo.txt notes/todo-backup.txt # 复制一份
mv notes/todo-backup.txt notes/draft.txt # 给副本改名
ls notes # 应看到 todo.txt 和 draft.txt目标若是已存在目录,命令通常把来源放进目录;目标若是文件路径,可能覆盖已有文件。初学时可用 cp -i、mv -i 在覆盖前询问。移动文件不会自动修改其他文本中引用的旧路径。
可以用熟悉的编辑器打开文件、修改后保存。文件管理器、编辑器与 Shell 操作的是同一份磁盘文件;编辑器里尚未保存的文字,cat 通常看不到。
也可以在终端编辑。若环境已提供 Nano,运行 nano notes/todo.txt,输入文字后按 Ctrl+O 保存、Enter 确认文件名、Ctrl+X 退出。Vim 也是常见终端编辑器,操作模式不同;可通过 vimtutor 学习,不必先掌握它才能阅读本文。
rm 删除指定文件。命令行删除通常不经过回收站,所以先确认路径和内容,再执行。
pwd # 确认当前目录
ls notes # 看清要删除的对象
rm -i notes/draft.txt # 输入 y 才删除;不想删则输入 n
ls notes # 确认结果,todo.txt 应仍在rm -r 递归删除目录及其内容,-f 减少提示并忽略不存在的文件。这些选项有合理用途,但目标范围可能很大;不清楚目录里有什么时先查看和备份,不把 rm -rf 当作通用修复命令。
日志按行记录事件。下面用五行虚构数据说明搜索:INFO 表示普通信息,WARN 表示警告,ERROR 表示错误。文件由代码创建,不需要另找素材。
先理解写法:cat 没有文件参数时可以读取标准输入;<<'EOF' 告诉 Shell,把接下来直到单独一行 EOF 的文本作为输入;> logs/app.log 再把 cat 输出的文本保存到文件。
cat > logs/app.log <<'EOF'
10:00 INFO page loaded
10:01 ERROR login timeout
10:02 INFO note saved
10:03 WARN connection slow
10:04 ERROR asset not found
EOF这种多行输入叫 here document。EOF 是自选的结束标记,不是单独运行的命令;换别的名字也可以,但开始和结束必须一致。结尾 EOF 要独占一行、顶格书写;开始标记带单引号,正文中的 $ 等字符就不会被当成变量展开。第一次看,把它理解为“把这一段文本交给 cat”即可。
grep 从文本中挑出匹配的行;wc -l 统计换行数量,适合这里每行都有换行的日志。
cat logs/app.log # 查看全部五行
grep 'ERROR' logs/app.log # 显示包含 ERROR 的两行
wc -l logs/app.log # 输出行数 5 和文件名grep 的输出:
10:01 ERROR login timeout
10:04 ERROR asset not found
常用选项有 grep -n 显示行号、grep -i 忽略大小写、grep -r 递归搜索目录。grep 默认把搜索内容当作正则表达式;寻找字面文字时可用 grep -F '文字' 文件名。
直接运行 grep,结果显示在终端。如果还想数出有几行,可以把结果交给 wc,不必手动复制、保存临时文件,再运行第二个程序。这个连接由管道 | 完成。
grep 'ERROR' logs/app.log | wc -l数据路线是:
日志 → grep 挑出 ERROR 行 → 管道传递这两行文本 → wc -l 数行 → 显示 2
左边程序的标准输出成为右边程序的标准输入。右边收到的是文本数据,不是左边命令的名字,也不是额外的文件名。通常只有最后一个程序的正常结果显示在终端。
再看排序和重复统计:
printf 'login\ndeploy\nlogin\n' | sort | uniq -cprintf 产生三行文字,sort 把相同文字排在一起,uniq 合并相邻重复行,-c 同时记录次数。输出有 1 deploy 和 2 login,前面可能有对齐空格。先 sort 是因为 uniq 只比较相邻行,不会自动寻找任意位置的重复内容。
程序通常有三条约定的数据通道,称为标准流:
| 名称 | 编号 | 默认作用 |
|---|---|---|
| 标准输入 stdin | 0 | 接收键盘输入,也可以从文件或管道接收 |
| 标准输出 stdout | 1 | 输出正常结果,通常显示在终端 |
| 标准错误 stderr | 2 | 输出错误或诊断信息,通常也显示在终端 |
stdout 和 stderr 都能显示在屏幕上,肉眼看着像同一种“输出”;但 Shell 可以分别安排它们去哪里。普通 | 连接 stdout,不自动把 stderr 也传给右侧程序。
重定向把默认通道改到另一个地方。例如,把本应显示在终端的结果写进文件,或把本应从键盘读取的数据改为从文件读取。管道连接两个程序,下面的重定向主要在程序和文件之间传递数据。
| 写法 | 作用 |
|---|---|
命令 > 文件 |
将 stdout 写入文件;不存在则创建,存在则覆盖 |
命令 >> 文件 |
将 stdout 追加到文件末尾 |
命令 < 文件 |
从文件读取 stdin |
命令 2> 文件 |
将 stderr 写入文件,stdout 仍按原方式输出 |
grep 'ERROR' logs/app.log > logs/errors.log # 保存结果,终端不再显示这两行
cat logs/errors.log # 查看保存的结果
printf '找到了两条错误\n' > notes/summary.txt
printf '需要分别查看原因\n' >> notes/summary.txt
cat notes/summary.txt # 两行;第二条没有覆盖第一条
wc -l < logs/app.log # 从 stdin 读日志,只输出数量 5wc -l logs/app.log 把文件名交给 wc,所以结果带文件名;wc -l < logs/app.log 由 Shell 打开文件作为输入,wc 没拿到文件名参数,所以只显示数量。
错误流可以单独保存:
ls missing-directory 2> logs/error-message.txt # 假设此目录不存在
cat logs/error-message.txt # 查看报错这没有修复错误,只是把报错保存下来。如果改用 >,ls 的错误通常仍显示在终端,因为它默认只改变 stdout。
Shell 先准备重定向目标,再运行命令。因此 sort file.txt > file.txt 会先把原文件截空,不能用来原地排序。应先输出到另一个文件,检查后再替换。
需要合并两种输出时,命令 > all.log 2>&1 表示先把 stdout 指向 all.log,再让 stderr 指向当前 stdout 的去处。顺序有意义,首次阅读先掌握前面的基本写法即可。
变量保存一个值,让多处命令使用同一个名字。例如,把长路径写进变量,以后使用和修改都更方便。
learner="新同学" # 赋值,等号两边不加空格
echo "$learner" # 取值,在名字前加 $,输出 新同学
project_dir="$HOME/shell-demo" # HOME 是系统提供的主目录变量
cd "$project_dir" # 使用这个路径定义时写 learner=...,取值时写 $learner 或 ${learner}。如果写成 learner = ...,Shell 会把 learner 当成命令,而不是赋值。
引号既能保留空格,也能控制变量是否展开。双引号允许 $变量 替换为值,同时保留值里的空格;单引号保留里面文字的字面含义。
echo "$learner" # 输出 新同学
echo '$learner' # 输出字面文字 $learner路径变量通常写成 "$project_dir"。不加引号,值里的空格可能把一个路径拆成多个参数。英文引号成对出现,少一边时 Shell 会继续等你输入。
普通 Shell 变量主要供当前 Shell 使用;环境变量还会传给由它启动的子程序。export 可以把变量放进环境:
export COURSE_NAME=qsc-training这通常只影响当前会话和后续子程序,不会自动永久保存到所有终端。关闭终端重新打开,临时设置的值可能不再存在。
PATH 是环境变量,记录 Shell 搜索外部程序的目录。输入命令名时,Shell 按规则查找可运行程序;这解释了为什么下载了一个文件,不一定就能直接输入它的名字运行。
printf '%s\n' "$PATH" # 搜索目录,在 Bash 环境中通常以冒号分隔
command -v bash # 查看 Bash 从哪里找到
type cd # cd 通常显示为 Shell 内建命令cd 等内建命令由 Shell 自己提供,不需要在 PATH 中找同名文件。遇到 command not found,先检查拼写、工具是否安装、搜索路径是否正确;不要用一个新目录覆盖整个 PATH。
程序结束时返回一个整数,叫退出码。通常 0 表示成功,非 0 表示失败或特殊结果;含义由程序定义,不是所有命令都用同一个失败数字。
$? 保存上一条命令的退出码,必须紧接着读取:
ls notes
echo $? # 目录存在时通常为 0
ls missing-directory
echo $? # 目录不存在时非 0中间若执行其他命令,$? 就变成那条命令的结果。另外,grep 找到匹配通常返回 0,没找到匹配返回 1;“没有匹配”不一定是程序损坏。grep 退出码说明
&& 表示左边成功才运行右边,|| 表示左边失败才运行右边。这样可以避免上一条失败后仍盲目继续。
mkdir -p notes/week1 && echo "目录准备好了"
cd missing-directory || echo "目录不存在,仍停留在原位置"普通 Bash 管道的退出码默认取最后一个程序,所以 grep ... | wc -l 返回 0,不代表前面每一步都成功。需要检查整条管道时可进一步学 set -o pipefail;先理解各程序返回值,再增加这类设置。
命令太多,不必一次背完。先理解要做什么,再查工具支持哪些选项,比凭印象拼参数可靠。
help cd # Bash 内建命令的帮助
man ls # 环境提供 man 时,打开 ls 手册;按 q 退出许多外部程序支持 命令 --help,但不是所有 macOS 工具都支持。Git Bash 可能没有完整 man,可以查官方文档。在线搜索时带上系统、工具名称和具体报错,避免照搬另一种 Shell 的写法。
| 报错或现象 | 含义与检查方向 |
|---|---|
command not found |
Shell 没找到命令;检查拼写、安装和 PATH |
No such file or directory |
路径不存在;先 pwd、ls,再核对路径和大小写 |
Permission denied |
当前操作没有所需权限;先确认文件和用户,不立即加 sudo |
出现续行提示 > |
引号或多行输入没结束;Ctrl+C 取消后检查符号 |
| 文件只剩新的一行 | 可能用了覆盖输出 >;需要追加时使用 >> |
| 同样命令在别人电脑能运行 | 核对 Shell、版本和系统,不能只比较窗口外观 |
向老师、中管或大模型求助时,可以提供“操作系统与 Shell、当前目录、完整命令、实际报错、期望结果”。分享前去掉密码和令牌;收到建议后先确认它会读写哪些文件,再运行。
在终端逐行输入是交互式使用;把命令保存到文件,让 Bash 按顺序执行,就得到脚本。脚本可以用参数处理不同文件,用条件检查输入,用循环减少重复代码。
下面把日志统计写成脚本:读取一份日志,分别数出 INFO、WARN、ERROR 的行数。代码在正文中,不依赖其他教程或下载包。
先认识写法:$# 是参数个数,$1 是第一个参数,${1:-logs/app.log} 表示未提供有效首参数时使用默认路径。[ -f "$log_file" ] 检查普通文件,[ -r "$log_file" ] 检查可读;方括号两侧要有空格。
if ...; then ...; fi 按条件执行;for ...; do ...; done 对多个值重复执行。$(命令) 叫命令替换,把命令的标准输出作为值,并去掉末尾换行。
用文本编辑器保存为 ~/shell-demo/scripts/summarize-log.sh,使用纯文本、UTF-8、LF 换行。代码块的三个反引号不是文件内容。
#!/usr/bin/env bash
# 首行是 shebang:直接运行时,env 从 PATH 寻找 Bash。
# 用法:bash scripts/summarize-log.sh [日志路径]
# 多余参数可能来自未加引号的路径;2 表示用法错误。
if [ "$#" -gt 1 ]; then
printf '用法:bash summarize-log.sh [日志路径]\n' >&2
exit 2
fi
# 不传参数时,相对于当前目录寻找 logs/app.log。
log_file="${1:-logs/app.log}"
if [ ! -f "$log_file" ] || [ ! -r "$log_file" ]; then
printf '日志不存在或不可读:%s\n' "$log_file" >&2
exit 1
fi
# 每次循环把 level 设置为一个等级,再执行相同的统计。
for level in INFO WARN ERROR; do
# 两侧空格对应示例中的等级字段;-c 输出匹配行数。
# 无匹配时 grep 返回 1,但仍输出 0;这里保留这个正常结果。
count=$(grep -c " $level " "$log_file")
printf '%s: %s\n' "$level" "$count"
done
exit 0 # 正常完成。从示例目录运行,默认读取此前正文创建的日志:
cd ~/shell-demo
bash scripts/summarize-log.sh
echo $? # 紧接着检查,应为 0脚本输出:
INFO: 2
WARN: 1
ERROR: 2
也可传入其他路径:bash scripts/summarize-log.sh "logs/another log.log"。引号保证含空格路径只传一个参数;文件不存在时提示错误并返回 1。默认相对路径以运行时的当前目录为起点,不自动以脚本所在目录为起点。
>&2 把错误提示送到 stderr,调用者就能分别保存统计结果和报错。exit 立即结束脚本,后面的命令不再执行。
还可以通过文件本身启动:
chmod u+x scripts/summarize-log.sh # 为文件所有者增加执行权限
./scripts/summarize-log.sh # ./ 指定当前目录下的文件bash 文件 是主动指定解释器;./文件 还依赖执行权限和首行 shebang。Git Bash 在 Windows 文件系统上的权限表现可能不同,用 bash 文件 即可。扩展名 .sh 是常见约定,不会自动替你选择正确 Shell。
这个脚本说明了命令、变量、条件和循环如何组合。它只统计符合示例格式的行,不判断错误是否解决;真实日志需要根据格式调整匹配规则。
查语法可读 GNU Bash 手册;想了解 PowerShell 命令和对象管道,可读 Microsoft PowerShell 文档。以后需要完整 Linux 环境时,再按 WSL 官方安装说明准备。