Neoverse-Docs

1.12 Shell 基础

Shell 概念、常用命令、重定向管道、权限用户与脚本入门

主要编写者:
本节 AI 摘要

本节区分终端Shell,介绍文件操作、搜索、权限、管道、重定向和 Bash 脚本。重点不是背命令,而是看懂参数、输入输出和执行结果,并在修改文件前先确认操作对象

INFO

图形界面适合交互式操作;而批量处理文件、管理远程服务器、重复执行流程时,Shell 更便于组合命令与记录步骤。

一、Shell 与终端

Shell 是读取并执行命令的程序。它会解析命令、展开变量和通配符,再启动相应程序或执行内建命令;终端则负责显示输入输出。两者经常一起使用,但不是同一个概念。

1.1 Shell 与终端的关系

概念说明
终端(Terminal)承载命令行输入输出的程序或会话
Shell终端里运行的命令解释器(bash、zsh、fish)
控制台(Console)原指直接连接计算机的操作台,如今也常泛指本地终端界面

可以把终端理解为“交互窗口”,把 Shell 理解为窗口中运行的“命令解释器”。

1.2 常见 Shell

Shell说明
bash许多 Linux 发行版常见,也是大量脚本的运行环境
zshmacOS 默认交互式 Shell,补全与定制能力丰富
fish开箱即用,自动补全强,但语法不兼容 bash
PowerShellWindows 上的现代 shell,面向对象,语法独立

学习提示

本节以 bash 为基准。zsh 的交互操作与 bash 有不少相似之处,但脚本语法和扩展并非完全兼容;脚本应明确解释器并在目标环境中测试。

1.3 现代交互 Shell 与提示符

bash 适合学习通用命令和编写可移植脚本。

zshfish 更偏向交互式使用。选择交互 Shell 时,应将“脚本解释器”和“日常命令行环境”分开考虑:脚本文件通过 shebang 指定 bash 或其他解释器,不会因为当前终端使用 zsh 或 fish 就自动改变语法。

Shell适合场景配置入口需要注意
bash通用脚本、服务器~/.bashrc启动文件读取规则随系统不同
zsh交互式补全、历史搜索、可定制提示符~/.zshrc与 Bash 相似但不完全兼容
fish语法高亮、补全、历史搜索开箱即用~/.config/fish/config.fish不遵循 POSIX 语法

1.3.1 zsh

在 Ubuntu / Debian 中可以按发行版提供的版本安装:

Bash
sudo apt update
sudo apt install zsh
zsh --version

macOS 通常已经提供 zsh;Homebrew 用户也可以按项目要求安装或更新。首次使用时先执行 zsh 进行体验,确认工具链和启动配置正常后,再考虑使用 chsh -s "$(command -v zsh)" 修改登录 Shell。修改前先确认该路径已在 /etc/shells 中,并保留一个可用的 Bash 会话作为恢复入口。与 Bash 类似但并非完全兼容:交互式配置通常放在 ~/.zshrc,登录配置还涉及 ~/.zprofile 等文件,迁移 Bash 配置时不能直接照搬。

1.3.2 fish

Bash
sudo apt update
sudo apt install fish
fish --version
fish

fish 的配置文件是 ~/.config/fish/config.fish。它使用 set 设置变量、使用括号执行命令替换,退出状态通过 $status 获取;例如:

Fish
vim --version >/dev/null 2>&1
if test $status -eq 0
    echo "Vim 可用"
end

fish 官方文档明确说明它不遵循 POSIX 标准。需要执行 Bash 命令或脚本时,应显式调用 bash,例如 bash -c 'printf "%s\n" "$HOME"'bash scripts/build.sh,不要把 Bash 配置文件直接复制到 fish 配置中。配置文件会在非交互场景也被读取,向其中加入输出内容或启动交互程序时应使用 status is-interactive 守卫,避免影响 SSH、SCP 等命令。

1.3.3 Starship:跨 Shell 提示符

Starship 是独立于具体 Shell 的提示符程序,能在 Bash、zsh、fish 等环境中显示当前目录、Git 分支和工作区状态。它只改变提示符,不会把 Bash、zsh 和 fish 变成同一种脚本语言。终端需要能显示相应符号;使用图标主题时还应安装并启用合适的 Nerd Font。

安装方式以 Starship 官方指南 为准。Ubuntu、macOS 和 Windows 的包管理方式不同,优先使用当前系统可信的软件包来源;安装后先确认命令可用:

Bash
starship --version

将对应初始化语句加入正在使用的 Shell 配置文件:

Bash
# Bash: ~/.bashrc
eval "$(starship init bash)"

# zsh: ~/.zshrc
eval "$(starship init zsh)"

fish 使用自己的管道和 source 语法:

~/.config/fish/config.fish
starship init fish | source

Starship 默认使用 ~/.config/starship.toml,配置格式为 TOML。下面这份配置只保留目录、Git 分支、Git 状态和命令结果提示,适合作为起点:

~/.config/starship.toml
"$schema" = "https://starship.rs/config-schema.json"
add_newline = false
format = "$directory$git_branch$git_status$character"

[directory]
truncation_length = 3

[git_branch]
format = "on [$symbol$branch]($style) "

[git_status]
format = "([$all_status$ahead_behind]($style) )"

[character]
success_symbol = "[➜](bold green) "
error_symbol = "[✗](bold red) "

配置文件可以放进个人配置仓库,但不要把令牌、密码或机器专用路径一并提交。修改后重新打开 Shell,或按当前 Shell 的方式重新读取配置;出现提示符异常时,可运行 bash --noprofile --norczsh -ffish --no-config,判断问题来自启动配置还是提示符程序。

1.4 打开终端

系统方式
WindowsWindows Terminal / Git Bash / WSL...
Linux从桌面环境的应用菜单打开终端;部分桌面环境支持 Ctrl + Alt + T
macOS启动台 → 终端,或 Cmd + Space 搜“terminal”

命令环境

本节的命令以 bash 为准(Linux / macOS / WSL / Git Bash 通用)。Windows 的 CMD 和 PowerShell 语法不同,不在本节范围内。建议用 WSL 或 Git Bash 练习。

二、提示符与命令结构

2.1 提示符

打开终端,会看到类似这样的提示符:

Text
SSJ@ubuntu:~/projects$

各部分含义:

Text
SSJ    @  ubuntu  :  ~/projects       $
 ↓          ↓           ↓             ↓
用户名    主机名     当前路径   普通用户提示符
  • ~ 表示用户主目录(示例中是 /home/SSJ
  • $ 表示普通用户,# 表示 root 用户(管理员)

2.2 命令结构

命令的基本结构:

Text
命令 [选项] [参数]

例如 ls -l /home

部分内容含义
命令ls列出目录
选项-llong 格式,显示详细信息
参数/home要列出的目录

选项通常以 -(短选项)或 --(长选项)开头,多个短选项可合并:ls -la 等同于 ls -l -a

从本机帮助开始

许多 GNU 命令支持 --help,例如 GNU/Linux 上的 ls --help

Shell 内建命令可尝试 help 命令,POSIX 系统也常用 man 命令

不同的系统和实现支持的选项可能不同,遇到不确定的命令应先查看当前环境的帮助。

三、常用命令详解

3.1 文件与目录操作

文件与目录操作命令速查

以下是 pwdlscdmkdircpmvrm 等常用命令的完整用法,可按需查看。

Bash
pwd                       # 查看当前路径
ls                        # 列出目录内容
ls -l                     # 详细信息(权限、大小、时间)
ls -a                     # 显示隐藏文件(以 . 开头)
ls -la                    # 组合:详细 + 全部
ls -lh                    # 以易读单位显示大小(KB、MB)
cd /home/SSJ              # 切换到绝对路径
cd projects               # 进入子目录(相对路径)
cd ..                     # 返回上一级
cd ~                      # 回主目录
cd -                      # 回到上一次所在目录
mkdir notes               # 创建文件夹
mkdir -p a/b/c            # 递归创建多层目录
touch test.txt            # 创建空文件(或更新时间戳)
cp file.txt backup.txt    # 复制文件
cp -r folder folder_backup # 递归复制目录
mv old.txt new.txt        # 重命名
mv file.txt ../           # 移动到上一级
rm file.txt               # 删除文件
rm -r folder              # 删除文件夹及其内容
rm -f file.txt            # 强制删除不提示
rm -ri folder             # 逐项确认后递归删除目录

危险命令

递归删除通常不经过回收站。执行前先用 pwdls -- 目标路径 确认位置与内容;变量或通配符参与路径时尤其要谨慎。初学阶段优先使用 rm -irm -ri 逐项确认,不复制来历不明的高权限删除命令。

3.2 查看文件内容

命令作用
cat file.txt输出全部内容
bat file.txt带语法高亮和行号的查看工具;交互终端中可调用分页器(Debian / Ubuntu 的软件包可能将命令安装为 batcat
less file.txt分页查看 (按 q 退出,/ 搜索)
head -n 20 file.txt前 20 行
tail -n 20 file.txt后 20 行
tail -f log.txt持续追踪文件末尾,常用于观察日志

3.3 查找

Bash
find . -name "*.cpp"           # 当前目录下所有 .cpp
find /home -name "*.md"        # 指定目录查找
find /var/log -type f -mtime +30   # 按完整 24 小时取整,匹配至少约 31 天未修改的普通文件
grep "error" log.txt           # 在文件中搜 "error"
grep -r "TODO" .               # 递归搜索当前目录
grep -i "error" log.txt        # 忽略大小写
grep -n "error" log.txt        # 显示行号
grep -v "info" log.txt         # 反向:显示不匹配的行
grep -c "error" log.txt        # 只输出匹配行数
grep -l "error" logs/*.txt     # 只输出包含匹配的文件名
which python                   # python 命令在哪
whereis gcc                    # gcc 相关文件位置
可选的搜索工具

fd 用正则模式搜索路径,ripgrep(命令 rg)递归搜索文件内容。

二者默认会遵循 .gitignore 并跳过隐藏路径。它们需要另行安装,匹配规则也不等同于 find -namegrep。先看各自的 --help,再根据仓库与搜索目标选择工具。

3.4 文本处理

命令作用
wc -l file.txt统计行数
wc -w file.txt统计单词数
sort file.txt排序
sort file.txt | uniq排序后去重
sort file.txt | uniq -c去重并统计每项出现次数
sed 's/old/new/g' file.txt把文件中所有 old 替换为 new
sed -i 's/old/new/g' file.txtGNU sed 直接修改原文件;BSD/macOS sed-i 参数写法不同
cut -d',' -f2 data.csv以逗号分隔,取第 2 列
awk '{print $1}' file.txt取每行第 1 个字段

3.5 系统信息

Bash
whoami              # 当前用户
date                # 当前时间
uptime              # 系统运行时间
df -h               # 磁盘使用情况
free -h             # 内存使用情况
top                 # 实时进程(按 q 退出)
ps aux              # 所有进程列表
kill PID            # 结束指定进程(PID 是进程号)

3.6 echo:输出文本

echo 把参数输出到标准输出(通常是屏幕)。最常见的两种特殊情况是变量替换和命令替换:

Bash
echo "Hello, Shell"
NAME="Alice"
echo "Hello, $NAME"          # 输出 Hello, Alice(变量替换)
echo "现在是 $(date)"         # 输出 date 命令的结果(命令替换)
echo 'Price is $100'         # 单引号禁止展开,原样输出 Price is $100
echo -n "无换行"              # 输出后不换行
echo "First" > file.txt      # 与重定向组合,创建文件
  • 双引号内的 $变量$(命令) 会被展开;单引号内的内容原样输出,适合输出 $、反引号等特殊字符。
  • 创建空文件更常用 touch,但 echo -n > empty.txt 也可以。

3.7 man 与 tldr:查阅命令手册

忘记命令用法时,两种常用的帮助来源:

来源说明
man 命令传统手册页,内容最完整;/关键词 搜索,按 n 下一个,q 退出
tldr 命令社区维护的简化手册,基于常见示例;适合 tarffmpeggit 等复杂命令

tldr 需要额外安装,常见包名为 tldr。看手册前先知道命令大致用途,再查参数,效率更高。

四、重定向与管道

4.1 重定向

默认情况下,命令结果输出到屏幕(标准输出)。用 > 可以重定向到文件:

Bash
ls -l > files.txt        # 输出写入文件(覆盖)
ls -l >> files.txt       # 输出追加到文件
echo "hello" > greet.txt # 把字符串写入文件
sort < unsorted.txt      # 从文件读取并排序
command 2> error.log     # 错误信息写入文件
command > out.log 2>&1   # 标准输出和错误都写入同一文件
符号作用
>标准输出覆盖写入文件
>>标准输出追加到文件
<从文件读取输入
2>标准错误写入文件
2>&1标准错误合并到标准输出

tee 能把输出同时写到屏幕和文件,适合“边看边存档”:

Bash
verbose_command | tee log.txt          # 屏幕与文件同时得到输出
verbose_command | tee log.txt | grep "ERROR"   # 存盘的同时继续过滤

4.2 管道

管道 | 把前一个命令的标准输出连接到后一个命令的标准输入,可以把多个文本处理步骤组合起来:

Bash
ls -l | grep "note"                              # 找出包含 "note" 的文件
ps aux | grep python                             # 找出 python 相关进程
find . -name "*.cpp" | wc -l                     # 统计当前目录 cpp 文件数量
history | awk '{print $2}' | sort | uniq -c | sort -rn | head -5  # 历史命令 Top 5

Unix 哲学

许多 Unix 工具专注于一种文本处理任务,并通过标准输入与标准输出组合。管道的好处在于,先确认每一步的输入输出,再把简单命令连成完整流程。

五、环境变量

5.1 查看环境变量

Bash
echo $PATH          # 查看单个变量
env                 # 查看所有环境变量
echo $HOME          # 用户主目录
echo $USER          # 用户名

5.2 设置环境变量

Bash
export MY_VAR="hello"              # 临时设置(只在当前终端有效)
echo $MY_VAR                       # 查看刚设置的变量
export PATH="$HOME/mybin:$PATH"     # 把个人命令目录加到 PATH 前面

5.3 永久生效

export 命令写进 Shell 配置文件,每次启动自动执行:

Shell配置文件
bash交互式非登录 Shell 常读取 ~/.bashrc;登录 Shell 从 ~/.bash_profile~/.bash_login~/.profile 中读取首个存在的文件
zsh交互式 Shell 通常读取 ~/.zshrc;其他启动文件由启动方式决定
Bash
nano ~/.bashrc                     # 编辑配置文件
# 在文件末尾添加:export PATH="$HOME/mybin:$PATH"
source ~/.bashrc                   # 让当前 Shell 重新读取配置

验证配置:

Bash
echo $PATH                         # 查看新路径是否生效
source 与重启终端

source ~/.bashrc 让配置在当前终端立即生效,不用关闭重开。但其他已打开的终端不受影响,需要重启或在那些终端里也执行一次 source

六、权限与用户

6.1 文件权限

Linux 文件权限分三组:所有者(user)、所属组(group)、其他人(other),每组有读(r)、写(w)、执行(x)权限。

Text
$ ls -l script.sh
-rwxr-xr-- 1 SSJ SSJ 120 Jun 27 10:00 script.sh

权限位 -rwxr-xr-- 解读:

Text
-        rwx       r-x       r--
类型     所有者    所属组    其他
文件     读写执行  读执行    只读

6.2 修改权限

chmod 命令,有数字和符号两种方式:

Bash
chmod 755 script.sh    # rwxr-xr-x(所有者全权,其他用户可读、可执行)
chmod 644 config.txt   # rw-r--r--(所有者可读写,其他用户只读)
chmod u+x script.sh    # 给文件所有者添加执行权限(符号方式)
chown SSJ:SSJ file.txt # 修改所有者
数字权限说明
7rwx读写执行
6rw-读写
5r-x读执行
4r--只读

6.3 sudo 提权

部分操作(安装软件、改系统文件)需要 root 权限。用 sudo 临时提权:

Bash
sudo apt update          # 以 root 身份执行
sudoedit /etc/hosts        # 使用当前编辑器安全地编辑系统文件

sudo 风险

sudo 会让命令以更高权限运行,错误的路径或参数可能覆盖系统配置、删除文件或改变权限。执行前应确认命令来源、目标路径和恢复方式,不要因为出现“权限不足”就机械地在命令前加 sudo

七、软件安装

不同发行版用不同的包管理器:

发行版包管理器示例
Ubuntu / Debianaptsudo apt install git
Fedoradnfsudo dnf install git
CentOS Stream / Rocky Linuxdnfsudo dnf install git
Archpacmansudo pacman -S git

Ubuntu 常用操作:

Bash
sudo apt update           # 更新软件源列表
sudo apt upgrade          # 升级已安装的软件
sudo apt install 包名      # 安装
sudo apt remove 包名       # 卸载
apt search 关键词          # 搜索

验证安装:

Bash
git --version             # 查看软件版本

八、提效技巧

8.1 历史命令

操作作用
/ 翻阅历史命令
Ctrl + R反向搜索历史(输入片段即匹配)
!!展开并立即执行上一条命令,使用前先确认历史内容
!关键词展开并立即执行匹配的历史命令,不建议初学时依赖
history查看全部历史

8.2 自动补全

Tab 可以补全命令、文件名和路径;按两次 Tab 通常会列出候选项。补全后仍要检查完整命令,尤其是在删除、移动和提权操作前。

8.3 别名 alias

交互式 Shell 中可以把常用命令设为短别名,并写进 ~/.bashrc。脚本不应依赖交互别名:

Bash
alias ll='ls -la'      # 用 ll 代替 ls -la
alias gs='git status'  # 用 gs 代替 git status
alias cls='clear'      # 用 cls 清屏

8.4 通配符

通配符含义示例
*匹配任意多个字符*.cpp(所有 .cpp 文件)
?匹配单个字符file?.txt(file1.txt、file2.txt)
[]匹配括号内任一字符project[123](project1、project2、project3)
Bash
printf '%s\n' *.tmp  # 先预览将被通配符匹配的文件
cp -- *.md backup/   # 确认后再复制,并用 -- 结束选项解析

要注意:通配符只用来匹配文件名,并不是正则表达式。正则能描述更复杂的模式(如“任意数字”“行首”),用途也更广,详见 1.7 文本编辑

九、脚本入门

把多条命令写进文件,就成了 Shell 脚本 (.sh),能重复执行。

9.1 第一个脚本

Bash
#!/usr/bin/env bash
# scripts/backup.sh
# Back up the notes directory to a timestamped archive.
# 将笔记目录备份为带时间戳的归档文件。
set -euo pipefail

source_dir="${HOME}/notes"
backup_dir="${HOME}/backups"
date_tag="$(date +%Y%m%d-%H%M%S)"
archive="${backup_dir}/notes-${date_tag}.tar.gz"

if [[ ! -d "$source_dir" ]]; then
  printf '目录不存在:%s\n' "$source_dir" >&2
  exit 1
fi

mkdir -p "$backup_dir"
tar -czf "$archive" -C "$HOME" notes
printf '备份完成:%s\n' "$archive"

使用方法:

Bash
chmod u+x scripts/backup.sh    # 给文件所有者添加执行权限
./scripts/backup.sh            # 运行

第一行是 shebang,用于选择可从当前 PATH 找到的 bash。set -euo pipefail 能让部分常见错误尽早暴露,但不能替代参数校验、日志和测试。

shebang(#!)是什么?

读作 /ˈʃiːbæŋ/,近似中文“希棒”。它是 #! 两个符号读法的合并:# 在英文中叫 hash,! 叫 bang,合称 “hash bang”,连读后就成了 shebang。

#! 写在脚本第一行开头,用来告诉操作系统用哪个解释器执行这个文件。它必须在文件最开头,前面不能有空格或空行。

#!/bin/bash 直接固定解释器的绝对路径。

#!/usr/bin/env bash 则先在 PATH 中查找 bash,兼容不同系统上解释器位置的差异,更常用。

没有 shebang 时也可以手动指定解释器运行,比如 bash script.sh。但如果直接执行 ./script.sh,操作系统就需要靠 shebang 来挑选解释器。

9.2 用脚本理解数据流向

Shell 脚本常用于把数据从一个阶段流向下一个阶段,这和版本控制里“工作区 → 暂存区 → 仓库”的流向很相似:

下面这个脚本演示如何用管道把三个命令串起来,完成“统计 cpp 文件中 TODO 数量并写入报告”的流程:

Bash
#!/usr/bin/env bash
# scripts/todo_count.sh
# Count TODO occurrences in C++ source files and write a report.
# 统计 C++ 源文件中的 TODO 数量并生成报告。
set -euo pipefail

todo_count="$(
  { grep -Roh --include='*.cpp' -o 'TODO' . || true; } | wc -l
)"
printf '总 TODO 数:%s\n' "$todo_count" > todo_report.txt
cat todo_report.txt

9.3 条件与循环

条件判断:[[ ... ]][ ... ] 更安全、支持更多特性,bash 脚本优先使用:

Bash
if [[ -f "config.txt" ]]; then
    echo "文件存在"
else
    echo "文件不存在"
fi

if [[ "$NAME" == "Alice" ]]; then
    echo "Hi Alice"
fi

常见的测试条件包括:-f(普通文件)、-d(目录)、-z(空字符串)、== / !=(字符串比较)、-eq / -lt / -gt(数值比较)。

循环:

Bash
# 遍历文件;没有匹配项时跳过字面量 *.txt
for file in *.txt; do
    [[ -e "$file" ]] || continue
    printf '处理 %s\n' "$file"
done

# 遍历固定数字序列(Bash)
for i in {1..5}; do
    printf '第 %s 次\n' "$i"
done

# while 循环
i=0
while [[ $i -lt 5 ]]; do
    printf 'i=%s\n' "$i"
    i=$((i + 1))
done

9.4 后台运行

耗时命令可以放到后台,终端不阻塞:

Bash
sleep 100 &             # 后台运行
last_pid=$!             # 立即保存这个后台进程的 PID
jobs                    # 查看当前 Shell 管理的后台任务
kill "$last_pid"        # 按 PID 结束该进程

学习路径

Shell 脚本不需要一次学精,先会读、会改简单脚本即可。等发现经常重复输入一组命令时,就到了写脚本的时候。在终端里编辑脚本文件的方法见 1.13 Shell 中的文本编辑

十、TODO 清单

  • 了解终端与 Shell 的区别
  • 熟练使用 pwdls--help / man / tldr 在执行前确认上下文
  • 熟练使用 echo 输出变量与命令替换结果,并区分单双引号
  • 了解管道与重定向组合只读命令,并理解覆盖与追加的区别,尝试使用 tee 边看边存档
  • 能安全地引用变量:"$variable"
  • 了解 Bash、zsh、fish 的交互配置与脚本解释器
  • 了解 shebang、set -euo pipefail 和脚本退出状态
  • 了解 ifforwhile 写简单的条件与循环
  • 删除、移动或提权前会先预览目标,确认无误后再执行
  • 尝试安装并初始化 Starship,了解并配置 starship.toml

十一、值得我们思考的问题

为什么示例总强调“先预览”?

Shell 会忠实执行展开后的路径和参数,而变量、通配符或当前目录可能与预期不一致。先运行只读命令查看目标,再执行写入或删除操作,这个习惯最值得养成。

如何判断陌生命令是否可靠?

先确认命令来自哪个程序,再查看本机的 --helpman 或项目官方文档。还要分清当前操作系统、Shell 和命令实现;同名命令在 GNU、BSD 与 BusyBox 环境中的选项可能不同。

命令行示例尤其需要验证——以官方 --help 输出和实际运行结果为准,不要轻信未经核实的片段;涉及删除、移动和提权的内容,务必先读懂再执行。

本页目录

讨论区

欢迎分享你的想法与建议