简介本资源是面向Linux初学者与中级运维人员的实战型学习资料聚焦命令行操作、系统配置与常见故障排查通过100个典型实例覆盖网络调用、Apache服务配置、错误代码解析等核心应用场景。压缩包共204个文件以195个HTML文档为主体系统组织了参数索引、优化选项、函数属性、机器约束及警告配置等模块化内容辅以3份PDF技术说明、2个ZIP/RAR工具包、1份Word文档含经典教程和1个EXE格式人物自述整体容量40.19MB结构清晰、便于按需查阅。已有2180人学习下载读者可直接获取完整可运行的代码示例、分步骤功能调用说明、配置参数详解及典型错误解决方案尤其适合在真实环境中边练边查、快速定位问题根源并建立系统性排错思维。1. 这不是命令速查表是把 Linux 当成「可编程工作台」来用的 100 个真实切口你有没有试过写完一个 Python 脚本想让它每天凌晨自动拉取日志、过滤关键词、生成摘要、发邮件——结果卡在crontab的环境变量不一致上调试两小时才发现PATH根本没加载.bashrc或者用find批量重命名文件正则写得飞起一执行却把整个目录树删空又或者rsync同步时加了-a却漏掉--delete导致旧文件越积越多磁盘悄无声息爆掉……这些不是“不会用”而是没真正把 Linux 当成一个可组合、可验证、可回滚的工作台。《Linux 实战 100 例》不是教你怎么背man ls它是一份由某实验室一线运维工程师整理的「故障现场还原集」每例都来自真实排障记录覆盖从单机开发环境搭建、服务进程守护、日志流式处理、批量文件治理到跨主机数据同步与轻量级监控闭环。适合刚脱离rm -rf *恐惧期、能写基础 Shell、但还没形成「Linux 思维链」的开发者、测试工程师和 DevOps 初学者——它不承诺让你秒变大神但能确保你下次遇到同类问题时第一反应不是搜 Stack Overflow而是翻出其中第 37、62、89 例对照着改三行参数就跑通。2. 从「能跑」到「稳跑」Shell 脚本工程化落地的四个硬性门槛2.1 为什么必须放弃裸写#!/bin/bash——入口校验与环境隔离是底线很多脚本开头只有一行#!/bin/bash看似干净实则埋雷。真实生产环境里/bin/bash可能不存在Alpine 用ash$HOME可能为空systemd service甚至date命令输出格式因 locale 不同而错乱2024-03-15vs15 Mar 2024。合格的实战脚本第一道关是「自证清白」#!/usr/bin/env bash set -euo pipefail # 1. 强制指定解释器路径避免 /bin/bash 在某些容器中缺失 # 2. set -e任一命令失败即退出-u引用未定义变量报错-o pipefail管道中任一环节失败即整体失败 # 3. 显式声明 IFS防止空格/换行符被意外分割 IFS$\n\t # 4. 环境探测确认关键工具存在且版本可用 for cmd in awk sed date rsync; do if ! command -v $cmd /dev/null; then echo ERROR: required command $cmd not found 2 exit 1 fi done # 5. 统一时间区避免日志时间混乱 export TZUTC提示set -euo pipefail是血泪经验凝结的「最小安全集」。-e防止错误静默吞没-u拦截$USER_NAME写成$USER_NAMEE这类低级 typo-o pipefail解决ls /nonexist | grep txt这种场景下ls失败但grep成功导致脚本误判为成功的经典陷阱。2.2 参数解析不能只靠$1 $2用getopts构建可维护的 CLI 接口手写if [[ $1 --force ]]; then FORCEtrue; shift; fi看似简单但当参数超过 5 个、支持长选项--output-dir、需要默认值和类型校验时代码会迅速失控。getopts是 POSIX 兼容的轻量方案虽不支持长选项但足够覆盖 90% 的实战需求#!/usr/bin/env bash set -euo pipefail # 定义参数规则f 表示 -f 选项无参数d: 表示 -d 选项后必须跟参数h 表示 -h帮助 while getopts fhd: opt; do case $opt in f) FORCEtrue ;; d) OUTPUT_DIR$OPTARG ;; h) echo Usage: $0 [-f] [-d DIR]; exit 0 ;; *) echo Unknown option: -$OPTARG 2; exit 1 ;; esac done # 移动位置参数使 $1 指向第一个非选项参数如输入文件 shift $((OPTIND-1)) # 校验必要参数 if [[ -z ${OUTPUT_DIR:-} ]]; then echo ERROR: -d DIR is required 2 exit 1 fi # 校验输入文件是否存在 if [[ ! -f $1 ]]; then echo ERROR: input file $1 not found 2 exit 1 fi参数说明getopts fhd:中的:表示该选项需接收参数-d /tmp无:表示开关型-f$OPTARG自动捕获-d后的值shift $((OPTIND-1))是关键OPTIND记录解析到第几个参数shift将已解析的选项从$中移除让后续逻辑能直接用$1、$2处理业务参数[[ -z ${OUTPUT_DIR:-} ]]使用${VAR:-}语法防未定义变量报错比[[ -z $OUTPUT_DIR ]]更健壮。2.3 文件操作的原子性保障用临时文件 mv替代直接覆盖echo new content config.conf看似无害但在高并发或大文件场景下可能造成读取进程看到「半截文件」。正确做法是「写新、校验、替换」三步# 错误示范直接覆盖存在竞态风险 # echo $NEW_CONTENT /etc/myapp/config.conf # 正确流程原子替换 CONFIG_FILE/etc/myapp/config.conf TEMP_FILE$(mktemp -p /tmp config.XXXXXX) # 创建带随机后缀的临时文件 # 1. 写入临时文件使用 重定向确保内容完整 echo $NEW_CONTENT $TEMP_FILE # 2. 可选校验临时文件内容如 JSON 格式检查 if ! jq empty $TEMP_FILE /dev/null; then echo ERROR: generated config is invalid JSON 2 rm -f $TEMP_FILE exit 1 fi # 3. 原子替换mv 是原子操作即使目标文件被其他进程读取也只会看到旧版或新版绝不会看到中间态 if ! mv $TEMP_FILE $CONFIG_FILE; then echo ERROR: failed to replace $CONFIG_FILE 2 rm -f $TEMP_FILE exit 1 fi # 4. 清理mv 已成功此处仅防异常 rm -f $TEMP_FILE注意mktemp -p /tmp指定临时目录避免在/etc下创建临时文件权限不足jq empty是轻量 JSON 校验若无jq可用python3 -m json.tool $TEMP_FILE /dev/null替代。2.4 日志记录不是echo log结构化时间戳与分级输出随手echo $(date): start processing /var/log/myscript.log会导致日志无法被journalctl或 ELK 收集。实战要求日志带 ISO8601 时间戳、进程 ID、级别标识并统一输出到stderr便于重定向分离log_info() { printf %s [%s] [INFO] %s\n $(date -u %Y-%m-%dT%H:%M:%SZ) $$ $* 2 } log_error() { printf %s [%s] [ERROR] %s\n $(date -u %Y-%m-%dT%H:%M:%SZ) $$ $* 2 } log_debug() { [[ ${DEBUG:-0} 1 ]] \ printf %s [%s] [DEBUG] %s\n $(date -u %Y-%m-%dT%H:%M:%SZ) $$ $* 2 } # 使用示例 log_info Starting backup for user $USER log_debug Full command: rsync -av --delete $SRC $DEST if ! rsync -av --delete $SRC $DEST; then log_error Rsync failed with exit code $? exit 1 fi关键点date -u %Y-%m-%dT%H:%M:%SZ输出 UTC 时间避免时区混乱$获取当前进程 PID用于关联日志与进程所有日志输出到2stderr主流程输出到 stdout方便./script.sh 2 error.log output.txt分离log_debug通过环境变量DEBUG1控制开关避免生产环境冗余日志。3. 进程守护与故障自愈绕开 systemd 的轻量级方案3.1 为什么nohup ./app 不足以支撑长期服务nohup只解决终端断开问题但无法处理进程崩溃重启、资源泄漏监控、启动依赖管理。某跨平台系统曾用nohup启动一个 Java 服务运行 3 天后因内存溢出 OOM 被 kernel 杀死无人知晓——因为nohup.out里只有启动日志崩溃瞬间无迹可寻。真正的守护需要「存活探测 自动拉起 崩溃快照」三位一体。3.2 用supervisord实现进程生命周期全托管无需 rootsupervisord是 Python 编写的进程管理工具无需 root 权限即可运行配置清晰状态可查# /home/user/myapp/supervisord.conf [supervisord] nodaemonfalse logfile/home/user/myapp/logs/supervisord.log pidfile/home/user/myapp/run/supervisord.pid [rpcinterface:supervisor] supervisor.rpcinterface_factory supervisor.rpcinterface:make_main_rpcinterface [supervisorctl] serverurlunix:///home/user/myapp/run/supervisor.sock [program:myapp-server] command/home/user/myapp/bin/start-server.sh directory/home/user/myapp useruser autostarttrue autorestarttrue startretries3 exitcodes0,2 stopsignalTERM stopwaitsecs10 redirect_stderrtrue stdout_logfile/home/user/myapp/logs/server.log stdout_logfile_maxbytes10MB stdout_logfile_backups5 environmentJAVA_HOME/usr/lib/jvm/java-11-openjdk-amd64配置要点解析autorestarttrue进程退出即重启无论退出码startretries3启动失败最多重试 3 次避免无限循环exitcodes0,2仅当退出码为 0 或 2 时视为正常退出其他码触发重启如 Java OOM 退出码通常为 143stopwaitsecs10发送TERM信号后等待 10 秒超时则发KILLenvironment注入环境变量解决JAVA_HOME等依赖问题stdout_logfile_*日志轮转策略防止单文件过大。启动与管理# 启动 supervisord后台运行 supervisord -c /home/user/myapp/supervisord.conf # 查看进程状态 supervisorctl -c /home/user/myapp/supervisord.conf status # 重启指定程序 supervisorctl -c /home/user/myapp/supervisord.conf restart myapp-server # 实时查看日志 supervisorctl -c /home/user/myapp/supervisord.conf tail -f myapp-server3.3 自研心跳检测脚本当supervisord不可用时的兜底方案某些嵌入式设备或老旧系统无法安装supervisord此时需用纯 Shell 实现「进程存活 崩溃快照」#!/usr/bin/env bash set -euo pipefail APP_PID_FILE/home/user/myapp/run/app.pid APP_LOG_DIR/home/user/myapp/logs CRASH_LOG_PREFIXcrash_$(date -u %Y%m%d_%H%M%S) # 检查进程是否存活 check_app_alive() { if [[ ! -f $APP_PID_FILE ]]; then return 1 fi local pid pid$(cat $APP_PID_FILE) if [[ -z $pid ]] || ! kill -0 $pid 2/dev/null; then return 1 fi return 0 } # 生成崩溃快照堆栈、内存、打开文件 capture_crash_snapshot() { local pid pid$(cat $APP_PID_FILE 2/dev/null) || return local crash_dir$APP_LOG_DIR/$CRASH_LOG_PREFIX mkdir -p $crash_dir # 1. 进程堆栈 if command -v pstack /dev/null; then pstack $pid $crash_dir/pstack.log 2/dev/null || true fi # 2. 内存映射 cat /proc/$pid/maps $crash_dir/maps.log 2/dev/null || true # 3. 打开文件列表 lsof -p $pid $crash_dir/lsof.log 2/dev/null || true # 4. 最近 100 行日志假设应用日志在固定路径 tail -n 100 /home/user/myapp/logs/app.log $crash_dir/last_logs.log 2/dev/null || true } # 主循环 while true; do if ! check_app_alive; then echo [$(date)] APP CRASHED! Capturing snapshot... 2 capture_crash_snapshot echo [$(date)] Restarting app... 2 # 启动应用并写入 PIDstart-app.sh 需确保写入 $APP_PID_FILE /home/user/myapp/bin/start-app.sh fi sleep 5 done此脚本核心价值在于「崩溃即留证」每次进程消失自动保存pstack、maps、lsof等关键诊断信息为后续分析提供原始依据而非仅记录「它挂了」。3.4 避坑进程守护的五个致命误区与修复现象原因解决supervisord启动后status显示STARTING卡住不动startsecs默认 10 秒若应用启动耗时超 10 秒supervisord 会判定启动失败并反复重启在[program]段添加startsecs30匹配实际启动时间同时用startretries1避免无限循环应用重启后stdout_logfile日志文件权限变为root:root普通用户无法写入supervisord以 root 启动时子进程继承其 uid/gid若未显式指定user子进程以 root 运行在[program]段强制设置userusername确保日志文件属主正确kill -9杀死supervisord后被管进程仍在运行supervisord默认不启用进程组管理子进程脱离其控制树在[supervisord]段添加nodaemonfalse确保前台运行并在[program]段添加killasgrouptrue和stopasgrouptrue启用组信号管理supervisorctl tail查看日志时内容延迟 30 秒才刷新supervisord默认每 30 秒轮询一次日志文件非实时修改[supervisord]段logfile_maxbytes和logfile_backups无效需在[program]段添加stdout_logfile_maxbytes0禁用轮转并配合stdout_logfile_backups0再用外部日志轮转工具如logrotate接管自研心跳脚本在cron中运行pstack报错Permission deniedcron环境下ptrace权限受限无法 attach 到其他进程改用ps命令检查进程状态ps -p $PID -o pid放弃pstack崩溃快照改用journalctl -u myapp --since 1 hour ago若用 systemd或直接读取应用自身日志4. 文件批量治理从find黑匣子到可验证的流水线4.1find不是万能钥匙理解-exec与xargs的语义差异find /data -name *.log -exec rm {} \;和find /data -name *.log | xargs rm看似等价但行为天差地别-exec ... \;对每个匹配文件单独执行一次rm安全但慢-exec ... 将多个文件名拼成一个rm命令如rm a.log b.log c.log高效但遇空格文件名会崩xargs默认以空格/换行分隔遇文件名含空格、换行、制表符时直接解析错误。正确姿势是「find -print0xargs -0」组合用\0作分隔符# 安全删除含空格的 .log 文件 find /data -type f -name *.log -print0 | xargs -0 rm -f # 安全复制并重命名将所有 .log 改为 .bak find /data -type f -name *.log -print0 | xargs -0 -I {} sh -c cp $1 ${1%.log}.bak _ {} # 安全统计文件数避免 wc -l 因文件名含换行而误计 find /data -type f -name *.log -print0 | wc -c | awk {print int($1/1)} # \0 字节计数即文件数提示-I {}中的{}是占位符sh -c ... _ {}将{}作为$1传入 shell_占位$0这是xargs传递参数的标准写法。4.2 批量重命名用rename工具替代脆弱的for循环手写for f in *.log; do mv $f ${f%.log}.bak; done在文件名含空格时失效且无法预览。renamePerl 版支持正则可预演# 1. 预演模式-n 参数只打印将要执行的操作不真实修改 rename -n s/\.log$/.bak/ *.log # 输出test file.log - test file.bak # 2. 真实执行 rename s/\.log$/.bak/ *.log # 3. 复杂场景将 2024-03-15-*.log 重命名为 log_20240315_*.txt rename -n s/^(\d{4})-(\d{2})-(\d{2})-(.*)\.log$/log_${1}${2}${3}_$4.txt/ 2024-03-15-*.log若系统无rename可用mmvsudo apt install mmv# mmv 支持通配符映射? 表示单字符* 表示多字符 mmv -n 2024-03-15-*.log log_20240315_#1.txt # -n 预演 mmv 2024-03-15-*.log log_20240315_#1.txt # 执行4.3 文件内容批量替换sed -i的跨平台陷阱与规避方案sed -i在 macOS 和 Linux 行为不一致macOS 要求-i 空字符串参数Linux 则sed -i即可。统一方案是用perl# 安全的跨平台文本替换原地修改 perl -i -pe s/old_string/new_string/g *.txt # 替换并备份生成 .bak 文件 perl -i.bak -pe s/old_string/new_string/g *.txt # 仅替换匹配行类似 sed /pattern/s/// perl -i -pe s/old/new/g if /^#.*config/ config.ini原理-i启用原地编辑-p自动打印每行-e执行表达式。perl在所有主流系统行为一致且正则引擎更强大。4.4 避坑文件批量操作的四大血泪现场现象原因解决find /path -name *.log -delete删除了不该删的目录-delete动作默认递归若/path下有access.log目录其下的文件也会被删改用-type f -delete显式限定文件类型或先用-print预览find /path -name *.log -type f -printxargs rm报错Argument list too long匹配文件过多超出系统ARG_MAX限制改用 find ... -print0rename s/foo/bar/ *.log报错No match但文件明明存在shell 展开*.log时无匹配文件rename收到字面量*.log而非文件名列表先用echo *.log确认 glob 是否生效或改用find . -name *.log -exec rename s/foo/bar/ {} sed -i s/old/new/g *.conf在 macOS 上失败macOSsed要求-i 否则将s/old/new/g当作备份后缀统一用perl -i -pe s/old/new/g *.conf或写兼容脚本if [[ $(uname) Darwin ]]; then sed -i s/old/new/g; else sed -i s/old/new/g; fi5. 跨主机数据同步rsync从「能传」到「可信传」的参数精调5.1rsync不是scp的替代品而是「差异同步引擎」scp file userhost:/path是全量拷贝rsync -av file userhost:/path是增量同步。但rsync的威力远不止于此——它能校验数据一致性、压缩传输、排除干扰、保留元数据。某图像处理 Demo 曾因rsync -av漏掉--delete导致远程服务器残留数千张废弃中间图磁盘告警频发。5.2 生产级同步命令模板七层防护#!/usr/bin/env bash set -euo pipefail SOURCE_DIR/data/images/ DEST_USERbackup DEST_HOST192.168.1.100 DEST_PATH/backup/images/ EXCLUDE_FILE/data/rsync-exclude.txt # 同步命令带详细注释 rsync \ --archive \ # -a等价于 -rlptgoD保留符号链接、权限、时间戳、所有者、组、设备文件、特殊文件 --compress \ # -z传输中压缩对文本有效对已压缩图片效果小 --partial \ # -P断点续传保留部分传输的文件 --delete \ # 删除目标端存在但源端不存在的文件关键 --exclude-from$EXCLUDE_FILE \ # 排除规则文件每行一个 glob 模式 --filterprotect .git/ \ # 保护 .git 目录不删除、不同步 --filterprotect .env \ # 保护 .env 文件 --timeout300 \ # 单次操作超时 300 秒防网络卡死 --contimeout30 \ # 连接超时 30 秒 --rshssh -o StrictHostKeyCheckingno -o ConnectTimeout10 \ # SSH 选项 --itemize-changes \ # -i输出每项变更的详细编码如 f 表示新增文件 --stats \ # 结束后输出统计传输量、速度、文件数 $SOURCE_DIR \ ${DEST_USER}${DEST_HOST}:${DEST_PATH}--itemize-changes输出解读关键编码文件传输方向表示本地→远程f文件d表示目录L表示符号链接九个表示文件内容、权限、所有者、组、时间戳、ACL、xattr、设备号、inode 号全部变更.无变更仅时间戳不同c内容变更f..t...... 表示仅时间戳不同。5.3 排除规则文件编写规范.gitignore语法复用rsync-exclude.txt应遵循.gitignore语法便于团队复用# 注释以 # 开头 # 忽略所有 .tmp 文件 *.tmp # 忽略 build 目录及其子目录 /build/ # 忽略 node_modules但保留其下的特定文件 node_modules/ !node_modules/package.json # 忽略日志但保留最近 7 天的 *.log !*.log.2024-03-*注意/build/中的/表示目录build/会匹配src/build/!开头表示反向排除白名单。5.4 验证同步结果用rsync --dry-run与--checksum双保险同步前必做两件事Dry-run 预演确认将要执行的操作Checksum 校验确保内容完全一致--archive只校验时间戳和大小默认跳过内容比对。# 1. 预演显示将要删除/新增/修改的文件 rsync --dry-run --archive --delete --exclude-from$EXCLUDE_FILE $SOURCE_DIR ${DEST_USER}${DEST_HOST}:${DEST_PATH} # 2. 同步后校验强制内容比对忽略时间戳 rsync --archive --checksum --dry-run --exclude-from$EXCLUDE_FILE $SOURCE_DIR ${DEST_USER}${DEST_HOST}:${DEST_PATH}若校验阶段输出为空说明源目标完全一致若有输出说明存在内容差异需排查网络丢包或存储损坏。5.5 避坑rsync同步的五个隐形杀手现象原因解决同步后远程文件时间戳比本地新rsync默认用--times保留时间戳但若远程系统时钟快于本地--times会强制写入未来时间添加--modify-window1允许 1 秒误差或同步前校准双方 NTP 时间--delete删除了远程重要文件但源端无对应文件排除规则文件未同步到远程导致rsync在远程端计算差异时未应用排除逻辑将--exclude-from改为--filterexclude .rsync-exclude并在源端放.rsync-exclude文件rsync会自动同步该文件并应用大文件同步中断后--partial产生的临时文件残留rsync断点续传时在目标端创建.filename.XXXXXX临时文件中断后未清理添加--partial-dir.rsync-partial将临时文件集中到.rsync-partial目录同步成功后自动清理rsync过程中 CPU 占用 100%拖慢其他服务rsync默认全力传输无资源限制添加--bwlimit10000限速 10MB/s或用ionice -c 2 -n 7降低 IO 优先级SSH 连接频繁断开同步失败默认 SSH 连接空闲超时通常 300 秒在--rsh中添加ssh -o ServerAliveInterval60 -o ServerAliveCountMax3保持连接活跃6. 日志流式处理用awk/sed/jq构建轻量级可观测性闭环6.1 不要cat log | grep error | awk {print $1,$4}用awk单次解析替代管道链多层管道cat→grep→awk效率低下且grep会提前过滤掉awk需要的上下文。awk本身支持模式匹配与字段提取应一气呵成# 低效三次进程创建重复读文件 cat /var/log/nginx/access.log | grep 50[0-9] | awk {print $1, $7, $9} # 高效单次解析内置模式匹配 awk $9 ~ /^50[0-9]$/ {print $1, $7, $9} /var/log/nginx/access.log # 进阶统计各 5xx 错误码出现次数 awk $9 ~ /^5[0-9][0-9]$/ {count[$9]} END {for (code in count) print code, count[code]} /var/log/nginx/access.logawk字段说明Nginx access log 默认空格分隔$1客户端 IP$7请求 URI$9HTTP 状态码$9 ~ /^50[0-9]$/正则匹配以50开头、后跟一位数字的三位码500, 501...509。6.2 JSON 日志实时解析jq的流式处理技巧现代应用常输出 JSON 日志如{level:error,msg:db timeout,service:api,ts:2024-03-15T08:30:00Z}。jq是 JSON 专用解析器比awk更精准# 实时监控错误日志tail -f jq 流式处理 tail -f /var/log/myapp/app.log | jq -r select(.level error) | \(.ts) [\(.service)] \(.msg) # 统计各服务错误数按 1 分钟窗口聚合 tail -f /var/log/myapp/app.log | jq -r select(.level error) | .ts[:16] | \ awk {count[$0]} {if (NR%600) {for (t in count) print t, count[t]; delete count}} # 提取错误堆栈.stack 字段可能很长只取前 5 行 jq -r select(.level error) | .stack | split(\n) | .[0:5] | join(\n) /var/log/myapp/app.log提示jq -r输出原始字符串无引号select()过滤\(.field)插值split(\n)切分数组.[0:5]取前 5 项。6.3 构建日志告警用awk触发阈值报警当错误率超过 5% 时发邮件无需引入 Prometheus#!/usr/bin/env bash LOG_FILE/var/log/nginx/access.log WINDOW_SIZE1000 # 滚动窗口大小 ERROR_THRESHOLD0.05 # 实时计算错误率 p a hrefhttps://download.csdn.net/download/ktv2000pad/4605700 stylecolor:#ec7500;font-size:14px; 本文还有配套的精品资源点击获取 /a img altmenu-r.4af5f7ec.gif srchttps://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif stylewidth:16px;margin-left:4px;vertical-align:text-bottom;cursor:text; /p SEO 优化官网定制响应式建站教育培训建站