跳转至

Linux 与命令行

一句话总结:命令行是 ML 工程的主战场——训练、部署、监控、调试全走终端;掌握 Shell、文件系统、权限、进程、包管理、环境变量与 SSH 是生存底线。

🗺️ 本章导览

  • 本章覆盖生产级软工:Linux → Git → 代码库设计 → 测试 → 部署与 DevOps
  • 01. Linux 与命令行 (本节): Shell、进程、权限、常用工具
  • 02. Git 与代码库管理:分支、合并、rebase、workflow
  • 03. 代码库设计:分层、模块化、依赖管理
  • 04. 测试与质量保证:单元/集成/E2E, TDD
  • 05. 部署与 DevOps: Docker、CI/CD、模型服务、MLOps

命令行是 ML 工程的核心界面:训练任务、服务器管理、数据流水线、集群运维全在终端里发生。本节覆盖 Shell、文件系统、权限、进程管理、包管理器、环境变量、SSH,以及每位 ML 工程师每天必用的核心命令。

  • 图形界面 (Graphical User Interface, GUI) 适合浏览网页,但要在凌晨两点跑一个远程 GPU 集群上的训练任务,它就完全不够用了。命令行 (或叫终端、Shell) 才是能扩展的工具:任何机器上都能用、可以脚本化、可以组合,从你的笔记本到云虚拟机再到高性能计算 (High-Performance Computing, HPC) 集群,它长的都一样。

  • 如果你是一位只会用 Jupyter Notebook 和 VS Code 按钮的 ML 工程师,那你正在丢掉巨大的生产力。每一套生产级 ML 系统的部署、监控、调试,都要靠命令行。

Shell

  • Shell 是一个从你这里读命令、然后去执行它的程序。它是你与操作系统 (Operating System, OS) 之间的中间人 (见第 13 章)。最常见的两个 Shell 是 bash (大多数 Linux 系统的默认 Shell) 和 zsh (macOS 的默认 Shell)。

  • 一个命令的形式:command [options] [arguments]

ls -la /home/user    # command=ls, options=-la, argument=/home/user
  • 选项 (options) 改变行为 (短选项一般以 - 开头,长选项以 -- 开头)。ls -l 用长格式列出,ls --all 显示隐藏文件。很多选项可以合并:ls -la 就是 -l 加 -a。

基本导航

pwd                 # 打印当前工作目录 (我在哪?)
ls                  # 列出当前目录里的文件
ls -la              # 列出所有文件 (含隐藏) 并显示详细信息
cd /path/to/dir     # 切换目录
cd ..               # 回到上一级
cd ~                # 回到家目录
cd -                # 回到上一次所在的目录

文件操作

cp source dest      # 复制文件
cp -r dir1 dir2     # 递归复制目录
mv old new          # 移动或重命名文件
rm file             # 删除文件 (没有回收站——删了就没了)
rm -rf dir          # 递归删除目录 (危险——不问你直接删)
mkdir -p a/b/c      # 创建嵌套目录
touch file.txt      # 创建空文件 (或更新时间戳)
cat file.txt        # 打印文件内容
head -n 20 file     # 前 20 行
tail -f logfile     # 实时跟随日志 (监控训练时的救命工具)
  • 坑点: rm -rf 是计算领域最危险的命令。没有撤销。回车前把路径检查三遍。永远不要跑 rm -rf / 或 rm -rf ~。

管道与重定向

  • Shell 的杀手锏是可组合性:用一堆小命令串起来干复杂的事情。

  • 管道 (|):把上一个命令的输出送进下一个命令作为输入。

cat training.log | grep "loss" | tail -5    # 含 "loss" 的最后 5 行
ps aux | grep python                        # 找到正在运行的 Python 进程
history | grep "docker"                     # 找之前跑过的 docker 命令
  • 重定向:把输出送到文件而不是屏幕。
python train.py > output.log 2>&1    # stdout 和 stderr 都写入文件
python train.py >> output.log        # 追加 (不覆盖)
echo "data" > file.txt               # 覆盖文件
echo "more" >> file.txt              # 追加到文件
  • 2>&1 把 stderr (文件描述符 2) 重定向到 stdout (文件描述符 1)。不加它,报错依然会出现在屏幕上,而只有正常输出会写入文件。

文本处理

grep "error" logfile.txt             # 找含 "error" 的行
grep -r "import torch" src/          # 在目录里递归搜索
grep -i "warning" log.txt            # 不区分大小写搜索
grep -c "epoch" log.txt              # 统计匹配的行数

wc -l file.txt                       # 统计行数
wc -w file.txt                       # 统计词数

sort data.txt                        # 按字典序排序
sort -n numbers.txt                  # 按数值排序
sort -u data.txt                     # 排序并去重
uniq -c sorted.txt                   # 统计连续重复的次数

cut -d',' -f2,3 data.csv            # 从 CSV 提取第 2 和第 3 列
awk '{print $1, $3}' data.txt       # 打印第 1 和第 3 个空白分隔的字段
sed 's/old/new/g' file.txt          # 把所有 "old" 替换成 "new"
  • 这些工具组合起来非常漂亮:
# 找出日志文件里出现最多的 10 种报错类型
grep "ERROR" app.log | awk -F': ' '{print $2}' | sort | uniq -c | sort -rn | head -10

查找文件

find . -name "*.py"                  # 找所有 Python 文件
find . -name "*.pyc" -delete         # 找到并删掉编译后的 Python 文件
find /data -size +100M               # 大于 100 MB 的文件
find . -mtime -1                     # 最近 24 小时修改过的文件

which python                         # python 可执行文件在哪?
locate filename                      # 快速搜索 (用的是预建索引)

文件系统层级

  • Linux 把一切都组织成一棵以 / 为根的树:
目录 用途
/ 整个文件系统的根
/home/user 你的个人文件、配置、项目
/etc 系统级配置文件
/usr 用户程序、库、文档
/usr/local 本地安装的软件 (不是通过包管理器装的)
/var 可变数据:日志 (/var/log)、数据库、缓存
/tmp 临时文件 (重启后清空)
/opt 可选的第三方软件
/proc 虚拟文件系统,暴露内核与进程信息
/dev 设备文件 (磁盘、GPU 都在这里)
  • 对 ML 而言:训练数据通常放在 /data 或 /home/user/data,模型放在 /home/user/models,而统一计算设备架构 (Compute Unified Device Architecture, CUDA) 装在 /usr/local/cuda。GPU 设备会以 /dev/nvidia0、/dev/nvidia1 等形式出现。

文件权限

  • 每个文件和目录都有三种权限,分别针对三类用户:
权限 文件 目录
r (读) 查看内容 列出内容
w (写) 修改内容 在里面创建/删除文件
x (执行) 作为程序运行 进入 (cd 进去) 目录
  • 三类用户:所有者 (owner, u)、用户组 (group, g)、其他人 (others, o)。
ls -l script.py
# -rwxr-xr-- 1 henry ml_team 2048 Mar 28 script.py
#  ^^^         所有者权限: rwx (读、写、执行)
#     ^^^      用户组权限: r-x (读、执行, 不能写)
#        ^^^   其他人权限: r-- (只读)
chmod 755 script.py       # 所有者=rwx, 组=rx, 其他人=rx
chmod +x script.py        # 给所有人加执行权限
chmod u+w,g-w file.txt    # 给所有者加写, 给组去掉写
chown henry:ml_team file  # 更改所有者与组
  • 坑点:一个开头写着 #!/usr/bin/env python3 的 Python 脚本,想作为 ./script.py 运行必须有执行权限 (chmod +x)。没有的话,你只能用 python3 script.py。

进程管理

  • 进程 就是一个正在运行的程序 (见第 13 章)。Shell 给了你一堆管理进程的工具:
ps aux                    # 列出所有正在运行的进程
ps aux | grep python      # 找 Python 进程
top                       # 实时进程监视器 (CPU、内存)
htop                      # top 的更好版本 (需单独安装)
nvidia-smi                # GPU 用量 (ML 必备)
watch -n 1 nvidia-smi     # 每秒刷新一次 nvidia-smi

kill PID                  # 优雅地终止进程
kill -9 PID               # 强杀 (优雅终止失败时用)
killall python            # 杀掉所有 Python 进程

# 后台运行
python train.py &                    # 后台运行
nohup python train.py > log.txt &    # 后台运行, 登出后依然存活
  • nohup 对 ML 训练至关重要:不加它,你 SSH 断开的一刻训练任务就被杀掉了。nohup 让进程脱离终端。

  • screen 和 tmux 是终端复用器,能创建持久会话。你可以在 tmux 会话里开始训练,断开 SSH,稍后再连回来,会话 (以及训练) 还在跑。

tmux new -s training          # 创建带名字的会话
# ... 开始训练 ...
# Ctrl+B, 然后 D              # 从会话分离
tmux attach -t training       # 稍后重连 (哪怕 SSH 断了再重连也行)
tmux ls                       # 列出会话

包管理器

  • 系统包 (OS 层的软件):
# Debian/Ubuntu
sudo apt update               # 刷新包列表
sudo apt install htop         # 安装一个包
sudo apt upgrade              # 升级所有包

# macOS
brew install wget             # 通过 Homebrew 安装
  • Python 包:
pip install torch             # 从 PyPI 安装
pip install -e .              # 以可编辑模式安装当前项目
pip install -r requirements.txt  # 从依赖文件安装
pip freeze > requirements.txt    # 导出已安装的包

# Conda (适合处理像 CUDA 这种复杂依赖)
conda create -n myenv python=3.11
conda activate myenv
conda install pytorch torchvision cudatoolkit=12.1 -c pytorch
  • 坑点:永远不要 pip install 到系统 Python 里。要用虚拟环境 (python -m venv env、conda create 或 uv venv)。系统 Python 是 OS 工具共用的,弄坏它可能把整个系统弄挂。

环境变量

  • 环境变量是所有程序都能访问的键值对。它不改代码就能配置行为。
export CUDA_VISIBLE_DEVICES=0,1    # 只用 GPU 0 和 1
export PYTHONPATH=/home/user/src   # 加到 Python 的 import 路径
export WANDB_API_KEY=abc123        # Weights & Biases 的 API Key

echo $PATH                         # 看当前 PATH
export PATH=$PATH:/usr/local/cuda/bin  # 把 CUDA 加到 PATH
  • .bashrc (或 .zshrc):每次你打开 Shell 都会执行的命令。把你的 export 语句放这里就能持久生效。

  • .env 文件:项目专属的变量,由 python-dotenv 这类工具加载。把秘密 (API Key、数据库密码) 放在 .env 里,并把 .env 加进 .gitignore。永远不要把秘密提交进 git。

SSH (Secure Shell)

  • SSH 通过加密通道把你连到远程机器。这是你访问云虚拟机、GPU 服务器、HPC 集群的通道。
ssh user@hostname              # 连接到远程机器
ssh -i ~/.ssh/key.pem user@ip  # 用指定密钥连接
ssh -L 8888:localhost:8888 user@server  # 端口转发 (远程 Jupyter 打到本地)
  • SSH 密钥 (公钥/私钥对) 代替密码:
ssh-keygen -t ed25519          # 生成密钥对
ssh-copy-id user@server        # 把公钥复制到服务器
# 现在 SSH 不需要输密码了
  • SSH 配置 (~/.ssh/config) 保存连接细节:
Host gpu-server
    HostName 10.0.1.42
    User henry
    IdentityFile ~/.ssh/gpu_key
    LocalForward 8888 localhost:8888
  • 之后一句 ssh gpu-server 就能带上这些配置自动连过去。

  • scp 和 rsync 用来在机器之间传输文件:

scp model.pt user@server:/data/models/     # 拷贝文件到远程
scp -r user@server:/data/results/ ./       # 从远程拷贝目录
rsync -avz --progress data/ user@server:/data/  # 带进度同步 (比 scp 聪明)

ML 常用命令速查

# GPU 监控
nvidia-smi                                   # GPU 用量快照
watch -n 1 nvidia-smi                        # 实时监控
gpustat                                      # 更干净的 GPU 概览 (pip install gpustat)

# 训练管理
nohup python train.py > train.log 2>&1 &     # 后台训练, 登出也不死
tail -f train.log                            # 监控训练输出
kill %1                                      # 杀掉最后一个后台任务

# 磁盘用量 (数据集很大)
df -h                                        # 所有挂载点的磁盘空间
du -sh /data/*                               # /data 里各项的大小
du -sh --max-depth=1 .                       # 各子目录的大小

# 内存
free -h                                      # 内存使用
cat /proc/meminfo                            # 详细内存信息

# 网络
curl -O https://example.com/dataset.tar.gz   # 下载文件
wget https://example.com/model.bin           # 另一个下载器
curl -X POST http://localhost:8080/predict \
    -H "Content-Type: application/json" \
    -d '{"text": "hello"}'                   # 测一下模型服务的接口

# 归档
tar -czf archive.tar.gz directory/           # 压缩
tar -xzf archive.tar.gz                      # 解压
zip -r archive.zip directory/                # zip 压缩
unzip archive.zip                            # zip 解压

# 快速看数据
head -5 data.csv                             # CSV 前 5 行
wc -l data.csv                               # 数一下有多少行
cut -d',' -f1 data.csv | sort -u | wc -l    # 数第 1 列有多少个不同的值

📌 本节要点

  • Shell 是可组合的:小命令 + 管道 + 重定向,就能拼出复杂流水线,抵得上一堆一次性脚本。
  • rm -rf 无撤销:尤其在生产机上,回车前把路径检查三遍,别对 / 或 ~ 下手。
  • nohup + tmux 是训练标配:让长任务在 SSH 断开、终端关闭后依然存活,保住你的 GPU 时长。
  • 权限三元组 rwx / ugo:脚本要能 ./script.py 直接跑,记得 chmod +x。
  • 文件系统层级要记熟: /etc 配置、/var/log 日志、/dev/nvidia* GPU 设备、/usr/local/cuda CUDA 安装路径。
  • 不要污染系统 Python:用 venv、conda 或 uv 建虚拟环境,把 pip install 关在里面。
  • 环境变量隔离配置与代码: .env 存秘密、.bashrc 存持久 export、CUDA_VISIBLE_DEVICES 控制可见 GPU。
  • SSH 密钥 + ~/.ssh/config:免密码登录 + 一句 ssh gpu-server 直连,传文件优先用 rsync -avz --progress。
  • 文本处理黄金组合: grep | awk | sort | uniq -c | sort -rn | head 五连击,日志分析核弹级。
  • 监控命令别忘: nvidia-smi 看 GPU、htop 看 CPU/内存、df -h 与 du -sh 看磁盘,训练前后各看一遍。