Linux软件编程基础:Shell命令、脚本与系统管理实战

发布时间:2026/9/15 5:39:43
Linux软件编程基础:Shell命令、脚本与系统管理实战 Day21学习计划走到了Linux软件编程基础。今天没去啃那些抽象的内核源码而是老老实实把Shell命令、脚本和系统管理实操过了一遍。说实话这套东西看起来基础一旦用起来恰恰是决定日常工作效率的关键。不管你是刚装好Linux虚拟机的新手还是工作中要上服务器处理日志、部署服务的老哥今天这篇都值得花几分钟过一遍。我这一天的安排很简单上午速刷高频命令下午写脚本自动化处理任务晚上集中做系统服务、用户权限和网络配置。三轮下来最大的感受就是命令不是靠背的而是靠“用错”记住的。接下来我就把这天的学习路线、核心细节和踩过的坑一起整理出来希望对正在走Linux这条路的人有点参考价值。1. 内容整体设计与思路拆解我见过不少人学Linux上来就背命令手册结果两天就放弃了。这次我给自己定了个原则每一个知识点都绑定一个真实任务任务驱动学习做完任务知识自然留下。这一天的整体设计就是围绕“让服务器能跑起来、脚本能跑通、服务能管理”展开的。1.1 从目标反推学习路径先想明白这一天到底要解决什么问题。我的目标有三个一是能快速在终端里处理文件、日志和打包解压二是会写Shell脚本去替代重复的人工操作三是知道怎么用systemd、用户权限和网络命令去管理系统。从这些目标反推学习路径就很清楚了先掌握高频命令保证能“走路”再学脚本语法能够“跑起来”最后落到系统管理真正“管起来”。这比按命令字典顺序学高效得多。我还给自己安排了一个小项目作为当天作业写一个备份脚本定时打包网站目录并保留最近7天的备份。这个作业把文件操作、日期处理、循环、条件判断、系统定时任务全部串起来了。1.2 环境准备与工具选型我建议准备一个独立环境来折腾别直接在生产服务器上学Day 1。我用的是虚拟机装Ubuntu Server干净、快照方便。如果你想轻量一点用WSLWindows Subsystem for Linux也完全可以体验接近原生Linux。想体验国内团队维护的发行版openEuler、麒麟、UOS这些也可以装在虚拟机里试试。终端工具方面Windows下我常用FinalShell因为它自带SFTP和图形化资源监控对新手很友好。熟悉之后其实直接用OpenSSH加系统自带终端就行。编辑脚本我推荐两个一是终端里用vim二是用VS Code的Remote-SSH插件远程打开服务器上的脚本文件写起来舒服很多。vim本身不复杂但初次使用一定要了解“普通模式、插入模式、命令模式”这三个状态不然连退出都成问题。新手如果实在不习惯先装nano也行但后面写复杂脚本还是得回vim。环境里我还提前准备了bash、coreutils、tar、grep、sed、awk这些基础工具Ubuntu默认基本都带。另外我习惯安装一个btop或htop用来实时看CPU和内存排查问题时非常直观。2. 高频Shell命令与脚本语法从能用到会写这一章节是当天的主线。我只挑那些日常使用频率最高的命令来精讲重点讲“为什么这样用”而不是简单罗列参数。2.1 高频命令速查按场景分组记忆把命令按场景分组比按首字母排序好记得多。下面这个表是我自己梳理的常用命令速查表适合贴在终端旁边快速查阅。场景常见命令典型用法文件目录ls、cd、pwd、mkdir、rm、cp、mvls -lah 查看详细属性mv 也能重命名内容查看cat、tac、less、head、tailtail -f 实时跟踪日志文本处理grep、sed、awk、cut、sort、uniqgrep -rn 关键词 /var/log查找定位find、which、whereis、locatefind /data -name *.log -mtime 7压缩解压tar、zip、unziptar -czvf demo.tar.gz /data磁盘内存df、du、free、top、iostatdf -hdu -sh *free -h网络查询ip、ss、ping、curl、wgetss -lntp 查看监听端口进程管理ps、kill、pkill、jobsps aux | grep nginx帮助文档man、info、--helpman tar我重点说三个我当天“用错才有印象”的命令。第一个是tar。有人分不清-c和-x记法很简单c是create创建归档x是eXtract提取所以打包用tar -czvf backup.tar.gz /data解包用tar -xzvf backup.tar.gz。其中的z表示gzip压缩v是显示详情f必须放最后指定文件名。第二个是grep。日常排查日志时grep -i忽略大小写、grep -n带行号、grep -A 5 -B 5显示匹配行的前五行和后五行这三个参数最实用。比如突然发现接口报错直接grep -n -B 3 -A 3 ERROR app.log就能看到报错上下文。第三个是awk。很多人一听awk就头皮发麻其实只拿它做最简单的事比如按列取内容awk {print $1, $2} file或者按逗号分割日志字段awk -F , {print $1} file。这一天的脚本作业里我用awk完成了从备份日志里提取总耗时一行代码搞定。2.2 脚本骨架从第一行到for循环Shell脚本本身不神秘它就是把多条命令写进一个文件按顺序执行。但要想写得分寸恰当至少要掌握变量、条件、循环、函数和参数传递。我总结了一个“懒人脚本骨架”每次接到新任务都先套这个模子#!/bin/bash # 脚本说明写这里任务目标、作者、日期 set -euo pipefail # 变量区 BACKUP_DIR/data/backup RETENTION_DAYS7 # 引入公共函数 # source /etc/scripts/common.sh log() { echo $(date %F %T) $* } # 主逻辑 log 开始备份 tar -czf $BACKUP_DIR/www_$(date %F).tar.gz -C /var/www . # 清理旧文件 find $BACKUP_DIR -name *.tar.gz -mtime $RETENTION_DAYS -delete log 备份完成这个骨架里有几个地方新手容易写错我单独说。第一行#!/bin/bash叫shebang它告诉系统用bash解释执行。如果不写直接./script.sh会找不到解释器。变量赋值时等号两边不能有空格BACKUP_DIR/data/backup写错成BACKUP_DIR /data/backup就会变成执行命令。引用变量时统一写成$BACKUP_DIR加双引号是为了防止路径里有空格导致命令被拆开。如果路径里没有空格不写引号也能凑合但养成加引号的习惯能避免各种诡异报错。第二行我写的set -euo pipefail是个保险组合-e让脚本在遇到任何一条命令执行失败时立刻退出避免“带着错误继续跑”导致大麻烦-u提示你变量未定义时的报错pipefail让管道命令中任何一段失败都能被发现。脚本调试阶段这个组合帮了我大忙。for循环在热词里出现频率很高确实也是脚本里最常用的结构。语法很简单for i in {1..5}; do echo 当前次数$i done注意do前有分号或者换行写也行。更实用的方式是把文件列表循环处理for file in /var/log/nginx/*.log; do echo 处理文件$file done如果文件名里有空格一定要用$file不然会被拆成多个参数。条件判断这块最大的坑是空格和括号。我推荐直接用[[ ]]而不是[ ]前者语法更宽容还能用和||if [[ -f $file -s $file ]]; then echo 文件存在且不为空 fi-f判断文件是否存在-s判断大小是否不为空。判断目录用-d判断某个命令是否存在用command -v 命令名。另外脚本接收外部参数时$1、$2分别代表第一个、第二个参数$#代表参数个数$代表所有参数。有一个容易被忽略但功能很顺畅的命令叫shift它可以把参数位置整体左移原来的$2变成$1在循环里连续处理参数时极好用while [[ $# -gt 0 ]]; do case $1 in -d) DIR$2; shift 2 ;; -f) FORCE1; shift ;; *) shift ;; esac done这种模式我后来写部署脚本和git一键提交脚本时一直在用。2.3 脚本执行、定时任务与调试技巧写完脚本第一步是bash -n script.sh做语法检查这步只检查语法不执行内容非常安全。第二步可以用bash -x script.sh逐步跟踪执行过程它会打印每一条命令和变量值调试时挂在脚本最后跑完一眼就能看到哪个环节有问题。权限方面bash script.sh不需要执行权限就可以跑但直接./script.sh需要chmod x script.sh。我建议脚本自己开发时两种方式都试一次免得部署到新环境时报Permission denied。定时任务用crontab管理。通过crontab -e编辑当前用户的任务表下面这条表示每天凌晨2点执行备份脚本0 2 * * * /usr/local/sbin/backup.sh /var/log/backup.log 21注意脚本里要用绝对路径因为cron执行时PATH有限找不到某些命令。我遇到过脚本手动跑一切正常放cron里就报“找不到命令”最后才发现是环境变量的问题。解决方式是在脚本开头加上export PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin或者直接写死命令的绝对路径。调试时如果脚本中途卡住可以按快捷键加速排查CtrlC中断当前命令CtrlZ暂停当前命令回到终端再通过后台任务管理恢复。这个基本功关键时刻能救命尤其是在执行一个死循环时。3. 系统管理实战服务、权限与网络一次打通脚本写好了下一步就是让这个能力在系统里真正落地。系统管理这块我拆成服务管理、用户权限、网络配置三条线每条线都配上实战任务。3.1 systemd服务注册、启动与开机自启现代Linux基本上都使用systemd管理服务和开机启动项。很多人在查看服务状态时报错其实是不知道这三个命令是固定搭配systemctl start 服务名 systemctl enable 服务名 systemctl status 服务名start是立即启动enable是设置开机自启status是查看当前状态并给出关键日志。注意enable不会启动服务start不会设置开机自启两者经常需要同时执行。停止服务用systemctl stop重启服务用systemctl restart重新加载配置用systemctl reload或daemon-reload。我当天做了一个练习把一个自己写的demo-server.sh注册成systemd服务。流程如下先写一个可执行脚本比如/usr/local/bin/demo-server.sh内容可以是一个简单的循环#!/bin/bash while true; do echo demo server running at $(date) /var/log/demo-server.log sleep 10 done然后在/etc/systemd/system/目录下创建demo-server.service[Unit] DescriptionDemo Server Service Afternetwork.target [Service] ExecStart/usr/local/bin/demo-server.sh Restartalways RestartSec5 Usernobody [Install] WantedBymulti-user.target里面Afternetwork.target的意思是这个服务在网络服务启动后再启动避免脚本依赖网络时出现问题。Restartalways让进程意外退出后自动拉起线上服务一般都要加。Usernobody指定服务以普通用户身份运行不要用root降低安全风险。配置写好后依次执行systemctl daemon-reload systemctl start demo-server systemctl enable demo-server systemctl status demo-server日志查看也是重点journalctl -u demo-server -f可以实时跟踪这个服务的日志不用再去翻文件。如果服务频繁重启用systemctl status demo-server通常能在最后几行看到失败原因比如“Executable path does not exist”这种提示十有八九是脚本路径写错了。热词里还出现了containerd它是容器运行时本身也是由systemd来管理的。在部署k3s或Kubernetes相关节点时经常需要这些命令systemctl status containerd systemctl restart containerd journalctl -u containerd -n 100 --no-pager日志里如果出现failed to load cni config之类的字段说明容器网络插件没配好。排查思路同普通服务一致先用status看状态再用journalctl看日志不要一上来就瞎重启。3.2 用户与权限权限控制在生产环境的细节用户和权限看起来简单考究起来全是细节。创建用户的命令useradd -m -s /bin/bash zhangsan passwd zhangsan-m会同时创建家目录-s指定默认shell为bash。如果不写这两个参数用户会落在没有家目录的状态而且shell可能是sh登录体验很奇怪。把用户加入sudo组usermod -aG sudo zhangsan这里有个容易忽略的点如果用户已经登录新组要重新登录一次才生效。很多人改完组发现sudo还是不行就是因为没重新登录。删除用户时如果加上-r会连家目录和邮件池一起删userdel -r zhangsan权限这块我尽量不直接修改大目录的权限而是按最小权限原则。常见目录和文件的权限组合是755和644数字含义是所有者、属组、其他人然后按读4写2执行1相加。前缀强制加0或4或2或1是特殊权限新手阶段先不管。修改属主和属组是这两个chown zhangsan:develop /opt/app chmod -R 755 /opt/app-R递归很重要否则子目录没改到。日常运维中修改系统sudo配置时一定要用visudo命令它会检查语法避免因为配置写错导致sudo全线不可用。不要直接vim /etc/sudoers一旦写错可能连sudo都用不了。当天我还故意测试了一个坑把脚本权限设成777让所有用户可写很快就被同事提醒这有严重的安全隐患。正确的做法是脚本所有者用chown root:root然后用chmod 755让其他用户只读可执行。写权限永远不要给到所有人。3.3 网络配置与DNS排查网络排查是系统管理的重要环节。查看IP地址用ip addr查看路由用ip route查看端口监听用ss -lntp。这三个命令替代了老旧的ifconfig、route和netstat虽然有些发行版还保留老命令但多网卡、多IP环境下新命令更可靠。网络不通时很常见的排查链路是ping 跟路由 # 验证本机到网关通不通 ping 8.8.8.8 # 验证外网通不通注这里只是网络连通性的通用测试实际业务中如果要测试外网连通性我更建议用curl -I https://www.example.com来验证同时能看到HTTP响应状态。不要用ping外网域名来判断DNS是否正常因为ping本身不一定会触发域名解析的成功与否。配置DNS时经常遇到问题。Ubuntu下一般用systemd-resolved管理DNS直接修改/etc/resolv.conf会被覆盖。正确的做法取决于发行版版本一种是修改/etc/systemd/resolved.conf里的DNS行一种是使用netplan配置。比如Ubuntu的netplan配置在/etc/netplan/00-installer-config.yaml静态IP和DNS可以这样写network: version: 2 ethernets: ens33: dhcp4: no addresses: - 192.168.1.100/24 routes: - to: default via: 192.168.1.1 nameservers: addresses: - 223.5.5.5 - 114.114.114.114写好之后执行netplan apply生效。注意yaml文件对缩进要求很严格空格多一个少一个都会报错。很多人配置完DNS后一直不生效多半是没有重启systemd-resolved或者配置文件格式错误。防火墙规则也很关键。Ubuntu上用ufwCentOS用firewalld。基本命令是# ufw ufw allow 22/tcp ufw enable # firewalld systemctl enable --now firewalld firewall-cmd --permanent --add-port80/tcp firewall-cmd --reload如果在服务器上启动了nginx却从外面访问不到先检查端口是否监听再检查防火墙是否放行最后检查云安全组是否放行。这三个层次层层排查90%的端口问题都能定位出来。4. 常见问题与排查技巧实录这一天我在实践中踩了不少坑整理成速查表放在这里以后再遇到类似问题可以对照着做。问题现象常见原因解决办法bad interpreter: No such file or directory脚本文件是Windows换行符CRLFsed -i s/\r$// script.shPermission denied脚本没有执行权限chmod x script.shcommand not found命令不在PATH路径中检查PATH或使用绝对路径参数没传入脚本脚本内变量名写错在脚本头部加set -u并打印echo $1变量赋值为空赋值时等号两侧误加了空格去掉空格VARvaluegrep结果为空日志文件权限不够或编码不对先ls -l再sudo grepsystemd服务启动后立刻停止ExecStart路径错误或脚本权限不对systemctl status 服务名查看最后日志crontab不执行脚本任务里用了相对路径所有路径改为绝对路径4.1 shell脚本执行报错先查换行符和权限在Windows下用记事本或某些编辑器写脚本传到Linux后经常出现bad interpreter错误。本质是Windows换行符\r\n和Linux换行符\n不一致。排查时可以先把文件末尾的\r删掉最常用的命令是sed -i s/\r$// script.sh如果你用VS Code写脚本建议把右下角的“LF”设置成“CRLF”反过来统一用LF。也可以配一个.editorconfig强制换行符为LF从根源上防止问题。脚本执行权限问题的坑也很常见。有些人明明在服务器上sudo ./install.sh却提示Permission denied先检查文件是否有x权限。通过ls -l script.sh看第一列是不是-rwxr-xr-x。如果只有-rw-r--r--说明没有执行权限用chmod x script.sh加上就好。不要用bash script.sh绕过权限去跑绕过没问题但脚本内部如果有二进制程序需要执行权限还是绕不过。4.2 命令找不到多半是PATH的锅热词里有“npm : 无法将“npm”项识别为 cmdlet、函数、脚本文件”这种Windows环境下是命令位置没被自动识别其实Linux里也有类似的command not found。比如你用源码编译安装了Python或git如果安装目录不在PATH里就会找不到命令。PATH是系统查找命令的路径集合。查看当前PATH用echo $PATH临时追加路径用export PATH/usr/local/python3/bin:$PATH这种临时方式只对当前终端有效关闭后失效。永久修改需要写入配置文件。系统级环境变量写在/etc/profile或/etc/environment用户级环境变量写在~/.bashrc或~/.profile。注意/etc/profile和~/.bashrc的生效时机不同新开终端或source ~/.bashrc才会重新读取。有个细节容易被忽略如果你想覆盖系统自带的命令PATH的顺序很重要。export PATH/my/bin:$PATH把自定义目录放在前面系统会优先使用你的目录export PATH$PATH:/my/bin放在后面则系统自带命令优先。很多开发工具都要求放在前面比如你装了新版git或python想要优先用它就把新路径放在前面。热词里还有vim命令相关的搜索很多人初学vim会遇到退不出来的尴尬。教一个救命技巧按Esc进入普通模式输入:wq保存退出输入:q!不保存强退如果实在不记得直接按CtrlQ或CtrlC中断当前命令。不过只要平时多写脚本vim用熟了这些都不是问题。4.3 服务起不来的排查思路服务起不来的问题在Day21里占了很大篇幅。因为系统的服务管理逻辑并不复杂难的是如何快速定位到真正的原因。第一步systemctl status 服务名。它会告诉我们服务现在是什么状态是active (running)还是failed或者处于activating状态。如果failed往下翻通常有Error字段提示错误原因。第二步journalctl -u 服务名 -n 50 --no-pager查看最近50条日志。日志里可能直接说“端口被占用”或者“配置文件错误”这就比干猜高效得多。举一个我遇到的例子写了一个nginx服务启动时报Address already in use。用ss -lntp查看端口发现80端口被另一个进程占用。解决方法是停止占用进程或修改nginx监听端口。但如果你在服务器上跑着业务不建议直接kill -9先用ss -lntp看到是哪个PID再根据实际情况决定是否终止。服务配置里还想强调一句Restartalways虽然方便但如果是配置错误导致的启动失败systemd会无限循环去重启可能造成更严重的问题。所以调试阶段建议先把服务设置为Restartno等确认稳定后再改成Restartalways不然日志刷屏根本看不清报错。4.4 几个被忽略但非常实用的系统管理技巧这一天还积累了不少小技巧放在最后一起说。第一个是history命令。终端里输入history能看到历史命令!$代表上一条命令的最后一个参数!!代表上一条命令。比如你刚tar -czvf /data/backup.tar.gz /var/www下一句想备份到另一个目录可以直接!!再改参数。热词里有“shell的shift命令”前面讲参数处理时已经提到这里再补充一句shift常配合while循环用来解析复杂命令行参数是很实用的基础功。第二个是文件解压中文乱码。热词里有“linux 解压文件乱码”常见于Windows打的zip包。现代版本可以用unzip -O CP936 xxx.zip指定编码或者解压后用convmv转码。如果不想折腾下载zip包时尽量找GBK编码的或者上传前用7zip重新打包成UTF-8编码。第三个是在删除文件前做好确认。脚本里用find . -name *.tmp -delete这种命令要格外小心我习惯先打印要删除的文件列表确认无误再加-delete。或者用ls -l确认路径再执行删除。这个习惯帮我躲过好几次误删目录的麻烦。第四个是调试脚本时的“干部待遇”。脚本开头写好自己的日志函数所有关键步骤都输出时间和路径这样出现问题时直接看历史日志而不是临时在终端里试错。在我日常维护的备份脚本里每执行一步都会打日志一旦出问题能立刻定位到是哪一步出了差错。最后再分享一个当天的小发现这一天练到凌晨快收工的时候我发现每天重复敲的git提交命令其实完全可以写成脚本。把git add、git commit、git push串起来再带一个参数作为提交信息一键搞定。这么一写我突然理解了为什么很多运维老手喜欢“一切皆脚本”这句话——Shell脚本不是高深技术它是帮你把重复劳动降到零的杠杆。Day21学下来最大的收获不是记住了某个命令而是建立了“用Shell去解决问题”的思维。以后不管是服务部署、日志分析还是定时任务第一反应都会先想这个能不能写成脚本简化掉。如果你也在学Linux给你一个建议今天学的命令赶紧找一件实际的事比如备份某个目录、统计日志里的错误次数马上写出一个能跑的脚本哪怕只有几行。亲手把命令和脚本揉在一起你会发现自己突然就跨过了那个“懂但不会用”的阶段。