场景:SSH 连上服务器正装着依赖,突然下课/断网/下班——SSH 一断任务全没。screen 让任务脱离 SSH 独立运行,下课提包跑路不丢进度;reptyr 紧急补救忘开 screen 的翻车现场;du 排查磁盘被谁吃光。本文用四个命令逐一击破。
1. ssh-agent:免密 SSH 密钥管理
ssh-agent 是一个后台守护进程,用于缓存 SSH 私钥的解密密码(passphrase)。加载一次密钥后,后续所有 SSH 连接无需反复输入密码。
1.1 手动启动
# 启动 agent(输出环境变量)eval "$(ssh-agent -s)"# Agent pid 12345
# 添加密钥ssh-add ~/.ssh/id_ed25519# Enter passphrase for ~/.ssh/id_ed25519: ****# Identity added: ~/.ssh/id_ed25519
# 查看已加载的密钥ssh-add -l# 256 SHA256:xxxx... user@host (ED25519)1.2 常用参数
| 命令 / 参数 | 说明 |
|---|---|
ssh-agent -s | 启动 agent,输出 bash 可用的环境变量 |
ssh-agent -c | 启动 agent,输出 csh/tcsh 可用的环境变量 |
ssh-agent -k | 关闭当前 agent |
ssh-agent -t 3600 | 密钥缓存有效期(秒),默认永久 |
ssh-add <keyfile> | 添加指定私钥到 agent |
ssh-add -l | 列出已加载的密钥指纹 |
ssh-add -L | 列出已加载密钥的公钥 |
ssh-add -d <keyfile> | 从 agent 中移除指定密钥 |
ssh-add -D | 移除所有密钥 |
ssh-add -t 3600 | 添加密钥并设置缓存时间(秒) |
ssh-add -c | 添加密钥,每次使用需确认(部分系统不支持) |
1.3 配置 ssh-agent 自动启动
手动启动 agent 的问题是:每次新开终端都要重新来过。以下三种方案可按需选用。
方案一:~/.bashrc 自动复用(推荐)
在 ~/.bashrc 末尾添加,让所有终端共享同一个 agent 进程:
# ssh-agent 自动启动(仅启动一次,多终端复用)export SSH_AUTH_SOCK="${XDG_RUNTIME_DIR:-/tmp}/ssh-agent-$USER.sock"
if ! pgrep -u "$USER" ssh-agent > /dev/null; then eval "$(ssh-agent -s -a "$SSH_AUTH_SOCK")" > /dev/nullfi# 如果有 agent 但没有密钥,静默添加ssh-add -l >/dev/null 2>&1 || ssh-add ~/.ssh/id_ed25519 2>/dev/null解释:用
pgrep检查是否已有 agent 进程,没有则新建;通过-a指定固定 socket 路径,让所有终端访问同一个 agent。
方案二:systemd 用户服务(systemd 系统)
创建 ~/.config/systemd/user/ssh-agent.service:
[Unit]Description=SSH authentication agent
[Service]Type=simpleExecStart=/usr/bin/ssh-agent -D -a "${XDG_RUNTIME_DIR}/ssh-agent.sock"ExecStartPost=/usr/bin/ssh-add ~/.ssh/id_ed25519
[Install]WantedBy=default.target启用并启动:
systemctl --user daemon-reloadsystemctl --user enable --now ssh-agent.service然后在 ~/.bashrc 中设置环境变量即可:
export SSH_AUTH_SOCK="${XDG_RUNTIME_DIR}/ssh-agent.sock"方案三:桌面环境自动管理
大多数 Linux 桌面环境(GNOME、KDE、macOS)的会话管理器已自动启动 ssh-agent 或 gnome-keyring-daemon,无需手动配置。可通过以下命令验证:
echo $SSH_AUTH_SOCK# /run/user/1000/keyring/ssh → 桌面环境已管理
env | grep SSH1.4 agent forwarding(转发)
从机器 A SSH 到机器 B 时,让 B 也能复用 A 上的密钥:
# 连接时启用转发ssh -A user@remote_host
# 或在 ~/.ssh/config 中永久配置Host myserver HostName 192.168.1.100 ForwardAgent yes⚠️ 安全提醒:ForwardAgent 会让远程机器的 root 用户在连接期间使用你的密钥。仅在信任的服务器上开启。
2. screen:任务脱离 SSH 运行
screen 是一个终端复用器,允许你创建多个虚拟终端窗口,即使 SSH 断开,里面的任务也会继续运行。
2.1 安装
# Debian/Ubuntusudo apt install screen -y
# RHEL/CentOS/Fedorasudo dnf install screen -y2.2 基本使用
# 创建新会话(可命名)screen -S mytask
# 在 screen 中运行任务python train_model.py
# 安全脱离(detach):Ctrl+A 然后按 D
# 回到终端后,列出所有会话screen -ls# There is a screen on:# 12345.mytask (Detached)
# 重新连接(attach)screen -r mytask💡 只输
screen也能快速启动,screen 会自动生成一个pid.tty.host格式的会话名。进入后随时可以用Ctrl+A:sessionname 新名字重命名当前会话,后续再用screen -r 新名字附加上去。
2.3 常用参数
| 命令 | 说明 |
|---|---|
screen | 快速创建会话(自动生成名称) |
screen -S <name> | 创建命名会话 |
screen -ls | 列出所有 screen 会话 |
screen -r <name> | 恢复(attach)指定会话 |
screen -r <pid> | 按进程号恢复会话 |
screen -d <name> | 强制将 attached 会话转为 detached 状态 |
screen -d -r <name> | 强制 detach 后再 attach(抢回会话) |
screen -x <name> | 多终端共享模式(两人同时看同一画面) |
screen -X quit | 关闭指定会话 |
screen -wipe | 清理已死掉的会话记录 |
2.4 快捷键一览
进入 screen 后,所有操作以 Ctrl+A 为前缀键:
| 快捷键 | 功能 |
|---|---|
Ctrl+A D | 脱离(detach) |
Ctrl+A C | 创建新窗口 |
Ctrl+A N | 切换到下一个窗口 |
Ctrl+A P | 切换到上一个窗口 |
Ctrl+A " | 列出窗口列表(可切换) |
Ctrl+A A | 重命名当前窗口 |
Ctrl+A K | 关闭当前窗口 |
Ctrl+A [ | 进入滚动模式(翻阅输出) |
Ctrl+A W | 显示窗口列表(底部条) |
Ctrl+A 0-9 | 切换到指定编号的窗口 |
2.5 记录输出到文件
screen 自带
-L日志功能,但受程序输出缓冲影响,经常明明有输出文件却为空,排查和配置成本较高。如果想记录命令的输出,直接用 shell 重定向更简单可靠:
# 覆盖写入(每次清空旧内容)./task.sh > output.log 2>&1
# 追加写入(保留历史)./task.sh >> output.log 2>> error.log
# tee:同时看屏幕输出 + 写入文件./task.sh 2>&1 | tee output.log# 追加模式./task.sh 2>&1 | tee -a output.log| 写法 | stdout | stderr | 文件模式 | 屏幕可见 |
|---|---|---|---|---|
> file | 写入 file | 仍显示在屏幕 | 覆盖 | ❌ |
>> file | 追加到 file | 仍显示在屏幕 | 追加 | ❌ |
2>&1 > file | 写入 file | 写入 file | 覆盖 | ❌ |
2>&1 >> file | 追加到 file | 追加到 file | 追加 | ❌ |
2>&1 | tee file | 写入 file | 写入 file | 覆盖 | ✅ |
2>&1 | tee -a file | 追加到 file | 追加到 file | 追加 | ✅ |
2>&1是什么?2>表示 stderr 重定向,&1表示目标为「stdout 当前指向的位置」。整句意思:把 stderr 合并到 stdout,让它们走同一条路。
文件描述符 含义 0/ stdin标准输入 1/ stdout标准输出 2/ stderr标准错误 不加
2>&1有什么影响?Terminal window ./task.sh > log.txt # stdout → 文件, stderr → 屏幕(丢失!)./task.sh > log.txt 2>&1 # stdout + stderr → 文件(完整)不加的话报错信息不会进文件,排查问题时日志里只有正常输出,异常全丢了——这是最常见的日志遗漏原因。
2.6 配置建议 (~/.screenrc)
# 关闭烦人的启动提示startup_message off
# 始终显示窗口列表hardstatus alwayslastlinehardstatus string '%{= kG}[ %{G}%H %{g}][%= %{=kw}%?%-Lw%?%{r}(%{W}%n*%f%t%?(%u)%?%{r})%{w}%?%+Lw%?%?%= %{g}][%{B}%Y-%m-%d %{W}%c %{g}]'
# 回滚缓冲区行数defscrollback 10000
# 防呆:退出时不误关窗口bind q把
bind q设为空后,Ctrl+A Q就不会误关了,想退出用Ctrl+A K或直接exit。
2.7 重新连接后上翻输出
screen -r 附加上去后发现鼠标滚轮、终端滚动条都翻不动历史输出?这是 screen 最常见的新手困惑。原因:screen 维护自己的回滚缓冲区(scrollback buffer),终端的滚动条只能翻终端自身的输出,翻不到 screen 内部的历史。
解决方法很简单:进入 copy/scrollback 模式:
# 进入 copy 模式,方向键/j k 翻行,PgUp/PgDn 翻页Ctrl+A [注意是
Ctrl+A [(左方括号),不是Ctrl+A Esc。后者是 tmux 的快捷键,在 screen 中会报Must be on a window layer。
在 copy 模式下的操作方式(类 vi 键位):
| 按键 | 功能 |
|---|---|
↑ ↓ / j k | 上下逐行移动 |
Ctrl+F / Ctrl+B | 上/下翻页 |
PgUp / PgDn | 上/下翻半页 |
g / G | 跳到顶部/底部 |
/关键词 | 向下搜索 |
?关键词 | 向上搜索 |
n / N | 下一个/上一个匹配 |
Esc 或 Enter | 退出 copy 模式 |
缓冲区大小由 ~/.screenrc 中的 defscrollback 控制:
# 默认 100 行,建议加大defscrollback 10000改完新创建的 screen 窗口生效,已有窗口可在 screen 内执行 Ctrl+A :scrollback 10000 临时调整。
不想每次手动进 copy 模式? 启动任务时直接重定向输出到文件:
./task.sh > task.log 2>&1,然后用tail -f/less在外部终端直接翻看历史输出,体验更好。
3. reptyr:接管正在运行的进程
reptyr 可以把一个已经在终端中运行的进程”抓”进 screen/tmux 会话里。比如忘记用 screen 直接跑了 sudo apt upgrade,可以用 reptyr 把它迁移进去。
名字来源:Re-attach PTY + r → “重新挂接到伪终端”。PTY(pseudo-terminal)就是 Linux 里虚拟终端的缩写。记法:re-pty-r = 重新(re)挂到终端(pty)上。
3.1 安装
# Debian/Ubuntusudo apt install reptyr -y
# RHEL/Fedorasudo dnf install reptyr -y3.2 紧急补救:任务已在跑,马上要关电脑/断 SSH
这是最常见的翻车场景:一个耗时任务跑起来了,此刻你必须断开连接(关笔记本、切网络、下班走人),但没开 screen。补救流程如下:
# 第 1 步:在任务所在终端中,按 Ctrl+Z 暂停进程# (假设任务叫 mytask,暂停后会显示)# [1]+ 已停止 ./mytask
# 第 2 步:把进程放到后台继续跑bg# [1]+ ./mytask &
# 第 3 步:脱离 shell 的管控,避免退出 shell 时进程被杀disown -h %1
# 第 4 步:确认进程仍在运行(disown -h 后 jobs 仍可见)jobs -l# [1]+ 12345 运行中 ./mytask &
# 现在可以安全退出 SSH / 关闭终端了。关键说明:
| 步骤 | 作用 |
|---|---|
Ctrl+Z | 暂停进程,让你有机会操作 |
bg | 让进程在后台继续运行。不要用 fg,fg 拉回前台就没法脱离终端了 |
disown -h %1 | 标记进程为 SIGHUP 免疫,但仍保留在 jobs 列表中(方便下一步用 jobs -l 确认 PID) |
disown 的两种用法区别:
disown %1 # 完全移除:作业从 jobs 列表消失,shell 退出不杀进程disown -h %1 # 标记但不移除:作业仍显示在 jobs 列表中,shell 退出不杀进程disown %1 | disown -h %1 | |
|---|---|---|
| 行为 | 将作业从 shell 作业表彻底移除 | 保留在作业表中,但标记为SIGHUP 免疫 |
jobs 可见 | ❌ 不再显示 | ✅ 仍可见,但 bg/fg 对其无效 |
| shell 退出 | 不杀进程 | 不杀进程 |
| 典型场景 | 干净利落,不留痕迹 | 想事后用 jobs 看一眼 PID,又不想被 SIGHUP 杀掉 |
💡 对于「紧急补救 → 之后 reptyr 找回」这个场景,两者效果相同。推荐
disown无参数,干净省事。disown -h的好处是你退出前还能用jobs -l再看一眼 PID,方便记下来。
⚠️ 仅限断开 SSH 的场景。如果任务是跑在本地机器上,直接关机(poweroff)进程一定会死,
disown救不了。唯一的选择是休眠/挂起代替关机。
之后如何找回进程
重新 SSH 登录后,用 reptyr 接管:
# 找到进程 PIDpgrep -f mytask# 12345
# 先开 screenscreen -S rescue
# 在 screen 内接管reptyr 12345关于日志:中间这段输出能看到吗?
不能。 disown 后退出 SSH 的那段时间,进程的 stdout/stderr 指向一个已经不复存在的终端,输出直接丢弃(写入 /dev/null),无法恢复。
如果在意中间这段输出,三种补救思路:
# 思路 1(事前最佳):启动时就把输出重定向到文件./mytask > task.log 2>&1
# 思路 2(事后补救 — 高级):用 gdb 重定向已在运行的进程的输出# 需要安装 gdb,且进程需用调试符号编译gdb -p 12345 -batch \ -ex 'p dup2(open("/tmp/task.log", 577, 0644), 1)' \ -ex 'p dup2(open("/tmp/task.log", 577, 0644), 2)' \ -ex detach# 577 = O_WRONLY|O_CREAT|O_APPEND, 后续输出会写入 /tmp/task.log
# 思路 3(保底):reptyr 接管后马上在 screen 中开启日志# Ctrl+A H → 今后所有输出都记录到 screenlog.0💡 最佳实践:预期要跑长任务时,永远先
screen -S taskname。disown+reptyr是紧急补救手段,中间丢日志是无法避免的代价。
3.3 常规接管场景
如果不需要断开连接,只是想把当前终端的进程迁移到 screen 里(比如终端太乱、想组织到 screen 窗口中):
# 终端 1:运行一个命令ping google.com
# 1. Ctrl+Z 暂停# 2. bg 放后台bg
# 3. 查看 PIDjobs -l# [1]+ 12345 运行中 ping google.com &
# 4. 启动 screenscreen -S rescue
# 5. 在 screen 中接管reptyr 123453.4 权限问题解决
如果遇到 Unable to attach to pid:
# 临时允许非 root 用户使用 ptraceecho 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
# 永久生效echo "kernel.yama.ptrace_scope = 0" | sudo tee /etc/sysctl.d/10-ptrace.confsudo sysctl -p /etc/sysctl.d/10-ptrace.conf| ptrace_scope 值 | 含义 |
|---|---|
| 0 | 任何进程可 ptrace 任何同 UID 进程(最宽松) |
| 1 | 仅父进程可 ptrace 子进程(默认,限制 reptyr) |
| 2 | 仅 root 可用 ptrace(最严格) |
| 3 | 完全禁用 ptrace |
3.5 常用参数
| 命令 / 参数 | 说明 |
|---|---|
reptyr <PID> | 接管指定 PID 的进程 |
reptyr -T | 窃取目标整个终端会话(实验性,更可靠,会附加该终端所有进程) |
reptyr -s | 强制附加 fds 0-2,即使目标进程未挂载在 tty 上 |
reptyr -v | 显示版本号 |
reptyr -V | 输出详细调试信息 |
4. du:查看文件夹磁盘占用
du(Disk Usage)用于统计文件和目录占用的磁盘空间。它是排查磁盘空间不足的第一利器。
名字来源:Disk Usage(磁盘使用量)。两个字母,好记——就是”看看磁盘被谁用了”。同类命令还有
df(Disk Free,磁盘剩余空间)和dd(Data Duplicator,数据拷贝)。
4.1 基本用法
# 查看当前目录总大小du -sh .# 4.2G .
# 查看当前目录下各子目录大小(一层深度)du -sh */# 1.2G Documents/# 800M Downloads/# 2.1G Projects/4.2 完整参数表
| 参数 | 全称 | 说明 |
|---|---|---|
-h | --human-readable | 人类可读格式(K, M, G) |
-s | --summarize | 仅显示总计 |
-c | --total | 最后一行输出总和 |
-a | --all | 显示所有文件,而非仅目录 |
-d <N> | --max-depth=N | 限制递归深度 |
--time | 同时显示最后修改时间 | |
--time=ctime | 显示状态变更时间 / atime 访问时间 | |
-x | --one-file-system | 不跨文件系统(跳过挂载点) |
-L | --dereference | 追踪符号链接 |
--exclude=<模式> | 排除匹配的文件/目录 | |
--threshold=<大小> | 只显示大于指定大小的项(如 +100M) | |
-b | --bytes | 以字节为单位(纯数字,适合脚本处理) |
-B<N> | --block-size=N | 指定块大小(如 -BM = 1M 块) |
--apparent-size | 显示文件表观大小而非实际磁盘占用 | |
-0 | --null | 输出用 NULL 分隔(配合 xargs -0) |
4.3 实用场景及命令
排查根目录磁盘占用大户
# 从根目录开始,一层深度,按大小排序sudo du -h -d 1 / 2>/dev/null | sort -rh | head -20
# 输出示例:# 16G /# 8.4G /usr# 5.1G /var# 2.3G /home# 890M /opt查看当前目录下最大的 10 个子目录
du -sh * 2>/dev/null | sort -rh | head -10找出某个目录下的大文件(>100MB)
# 显示详细文件大小du -ah /path/to/dir | sort -rh | head -20
# 或仅显示大于 100M 的du -ah /path/to/dir --threshold=+100M | sort -rh不跨文件系统(跳过 /mnt、/media 等挂载点)
du -sh -x /*为什么重要:排查根分区爆满时,如果不加
-x,du会钻到挂载的外部硬盘、NFS 共享等子目录中,把它们的空间也算进来,导致混淆。
结合 find 精确排查
# 查找 /var 下大于 500M 的文件find /var -type f -size +500M -exec ls -lh {} \; 2>/dev/null
# 查找最近 7 天内修改过的大文件(>100M)find / -type f -size +100M -mtime -7 -exec ls -lh {} \; 2>/dev/null4.4 du vs df 的区别
du | df | |
|---|---|---|
| 用途 | 估算文件/目录的实际占用空间 | 查看文件系统层面的空间使用 |
| 来源 | 遍历目录树,累加文件大小 | 读取文件系统超级块中的元数据 |
| 场景 | ”哪个目录占了我的空间?" | "分区还有多少空间?“ |
| 差异 | 比 df 小(不含已删除但未释放的文件) | 比 du 大(含已删但仍占用的) |
# 对比两者差异df -h /# /dev/sda1 50G 42G 5.5G 89% /
du -sh / --exclude=/proc --exclude=/sys 2>/dev/null# 37G /# 相差 5G → 可能有进程持有已删除文件df 比 du 大很多时,通常是某进程仍持有已删除文件的句柄。排查方法:
# 查看已删除但仍被占用的文件sudo lsof +L1 | head -30
# 找到后重启对应进程或 kill 掉持有句柄的 PID4.5 ncdu:交互式 du(可选利器)
sudo apt install ncdu -y
# 交互式浏览ncdu /
# 导出分析报告ncdu -o disk_scan.json /
# 在另一台机器上查看ncdu -f disk_scan.json在
ncdu界面中,方向键导航、d删除、s按大小排序、n按名称排序,q退出。
5. 组合技:实战流程
场景:SSH 到服务器,想跑一个耗时脚本,中途网络断了就白费 —— 用 screen 兜底。
# 1. SSH 登录服务器ssh user@myserver
# 2. 启动 screen 会话screen -S work
# 3. 在 screen 中运行任务./long_running_script.sh
# 4. 安全脱离: Ctrl+A 然后 D
# 5. 断开 SSH,回家吃饭exit
# 6. 回家后重新 SSH 登录,恢复会话ssh user@myserverscreen -r work# 任务还在跑,输出完好参考链接
以下是可爱的评论们:

输入用户名和邮箱后自动检查登录状态。登录后用户名和邮箱将被绑定, 只可以修改头像和主页链接。