尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Linux进阶实操:管道、脚本、权限与终端定制的自由之道

Linux进阶实操:管道、脚本、权限与终端定制的自由之道 上篇我们聊到Linux的命令行不是一张命令清单而是一场持续的对话——你敲下一个指令系统还你一片天地。很多人把“玩Linux”误解成背参数、记快捷键但我更愿意把它比作学骑车一开始你盯着脚踏板和刹车后来你根本不会去想每个动作却能稳稳地在风里穿行。这篇下篇我想接着上篇的话题往下走不讲太多基础语法而是聊聊管道、脚本、权限、进程和终端定制——这些东西组合在一起才构成了Linux真正的自由感。适合给自己配环境、跑服务、写脚本的人参考如果你刚接触Linux上篇带你逛完了文件和目录这一篇就带你把这些碎片真正串起来。1. 管道与重定向把零散的指令串成一首完整的诗单独看ls、cat、grep每一个都只是“点一枪”。真正让Linux从工具升级成天地的是组合。而组合的第一步就是管道和重定向。我的理解是管道是用来连接人和机器的语法本质上就是前一条指令的输出直接喂给下一条指令当输入中间不需要落盘不需要手工复制一气呵成。1.1 管道像流水线一样把命令接起来先说最基本的形式cat /var/log/syslog | grep error | head -20这条命令的意思是读取系统日志 → 只保留包含error的行 → 只看前20行。三个原本独立的命令通过|串成了一条流水线。你可能说grep自己就能读文件为什么要cat再grep因为管道真正厉害的地方在于任意组合你可以ps aux | grep nginx也可以history | sort | uniq -c | sort -rn | head甚至可以把一个命令的输出通过管道送给任何愿意从标准输入里读数据的程序。我经常给新手打个比方管道就像工厂流水线每个工人只做一件事做完就传给下一个人。Linux的基本哲学是每个程序都只做好一件事并把结果留给别人用所以几乎所有的命令都约定俗成地遵守从标准输入读、往标准输出写的规则。这就是自由协作的模型。另外有个细节值得注意管道里的命令是同时运行的数据像水流一样持续流过而不是等前一个命令全部跑完再开工。这意味着你可以用tail -f配合grep实时过滤日志tail -f /var/log/syslog | grep nginx看到一条报错屏幕上立刻多一行不需要重启任何东西也不需要写脚本定时去检查。这种实时流动带来的快感是文件操作方式永远给不了的。1.2 重定向把杂音引开只留下你想看的如果说管道是把输出传给另一个程序重定向就是把输出写到文件里。Linux默认给每个进程准备了三个数据流标准输入0、标准输出1、标准错误2。很多人只认识结果遇到报错信息没有被重定向就一脸懵。举个例子# 覆盖写入文件 ls -l /etc etc_list.txt # 追加内容 ls -l /var etc_list.txt # 只想看错误信息 find / -name *.conf 2/dev/null | head -20 # 把正常输出和错误一起存进一个文件 command all.log 21这里最容易踩的坑有两个。一是把和搞混会直接覆盖整个文件如果你本来是想追加一不留神就把之前的记录清空了。我有个朋友调试配置时执行了echo something config.ini结果整个配置面板直接变成了一行字当场傻眼。所以拿不准的时候先cp config.ini config.ini.bak再用。二是漏掉21或2/dev/null如果不重定向错误脚本在cron里一旦遇到权限问题只会留下莫名其妙的空白日志。/dev/null是Linux里的黑洞所有写进去的东西都会消失。它不是没有意义的存在恰恰相反它的意义是让你只关注真正想关注的信息。排查问题的时候把无关干扰引到黑洞里是一种必要的克制。1.3 tee与xargs在传递中留住瞬间在组合中解决分歧管道很爽但有个尴尬数据流过去之后你就看不到它了。想边看边存用teeps aux | tee process.log | grep nginxtee像流水线上安装了一个分叉的监视器把当前数据原样存进process.log同时继续往下传。所以一边能存日志一边能实时看到经过筛选的内容非常适合调试。xargs则是解决另一类问题有些命令不读标准输入只接受命令参数。最典型的例子是wc -l你只find . -name *.txt | wc -l得到的是一个文件数量而不是每个文件的行数。要统计所有txt文件各自多少行得这样find . -name *.txt -print0 | xargs -0 wc -l-print0配合-0是为了防止文件名带空格时被拆错。这是xargs最常见的坑默认按空白字符分割遇到带空格的文件就会断成两截轻则统计错误重则误删文件。稳妥的做法要么加-0要么用find ... -exec代替。我不想把每个人都训练成xargs爱好者但至少要知道不带参数的xargs默认是等空格不等文件。2. 脚本与定时任务把自由从一次次的“手动敲击”里赎回来自由最大的敌人是重复。当同一组三条命令你每天都要敲一遍时就该写脚本了。脚本不是高深莫测的魔法它就是把命令一行行写进文件然后让机器替你去执行。2.1 第一个脚本从“记住命令”到“让机器记住你”一个最朴素的备份脚本长这样#!/bin/bash BACKUP_DIR~/backups DATE$(date %Y%m%d) mkdir -p $BACKUP_DIR tar -czf $BACKUP_DIR/site_$DATE.tar.gz /var/www/html find $BACKUP_DIR -name site_*.tar.gz -mtime 7 -delete echo backup done: $BACKUP_DIR/site_$DATE.tar.gz第一行#!/bin/bash非常重要它告诉系统用bash来读这个脚本。如果缺了它你执行./backup.sh会报错或者被当成别的解释器处理。$(date %Y%m%d)把当前日期嵌入文件名这样每天生成一个不同文件-mtime 7 -delete顺手把7天前的旧备份清理掉。保存后先chmod x backup.sh给执行权限然后./backup.sh就能跑了。脚本里的变量、条件、循环都没有太大玄机for i in {1..5}; do echo hello $i done if [ -f /etc/nginx/nginx.conf ]; then echo nginx config exists fi我觉得对新手来说最需要转变的心态是脚本不是在“编程”而是在“把一次性的事情变得可以重复”。你不需要先学会循环语法再写脚本你完全可以把三行命令先存进文件、手动执行一百次等某天发现这行命令总要在另一个目录里执行时再补一个cd或变量进去。2.2 crontab把重复的事交给未来的某个时刻脚本写好了仍然需要人肉去执行。真正让它跑起来的是crontab。执行crontab -e添加一行30 2 * * * /home/user/backup.sh /home/user/backup.log 21五段数字对应分钟、小时、日期、月份、星期。字段范围含义分钟0-59每小时的第几分执行小时0-23每天第几小时执行日期1-31每月的第几天执行月份1-12每年的第几月执行星期0-6每周第几天0为周日30 2 * * *就是每天凌晨2点30分。注意cron的环境变量极其精简它不会加载你.bashrc里的alias和PATH。所以脚本里的命令最好写绝对路径比如/usr/bin/tar或者在脚本开头统一export PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin。我见过很多次脚本手动跑没问题一进cron就报错的案例十有八九是PATH问题。另一个坑是日志。cron默认会把脚本的所有输出通过邮件发给本地用户如果系统没有配置邮件服务邮件通知会堆积成隐患。所以给脚本的 log 21不是可选项而是必需品。2.3 alias给命令起一个只有你懂的小名如果说脚本是批处理那alias就是快捷键。在~/.bashrc里写上一堆别名重启终端或source ~/.bashrc日常工作量立刻能降一个量级alias llls -alF alias ..cd .. alias gpgit pull alias gsgit status alias dpsdocker ps alias dpdocker compose alias pypython3 alias notevim ~/notes/linux.md我的建议是任何你一周内至少用五次的长命令都值得一个alias。比如装完Docker之后docker ps再配合fzf选容器ID实在太日常了一个dps就能省一截输入。Python也类似Ubuntu上python3明明就是那个python但总有人因为习惯问题来回敲错一个小小alias就没人再抱怨这事了。安全一点的alias是alias rmrm -i每次删除前都问一下刚开始觉得烦但经历过误删之后就会觉得香。真正的自由不是敲得更多而是想要什么顺手就能拿到。3. 权限与sudo自由不是为所欲为而是知道自己被信任浪漫的另一面是尊重边界。在Linux里权限不是网管为了限制你而设的枷锁它是一套让每个人都安全生活的契约。我第一次认认真真理解chmod三个数字时突然意识到这正是这台机器信任我的方式。3.1 chmod数字背后的意义rwx其实是三种协商先看一个常见的输出-rw-r--r-- 1 root root 1234 Jan 12 10:00 id_rsa第一段的10个字符里第一个是文件类型-普通文件、d目录、l符号链接后面9个字符每3个一组属主、属组、其他人。每个组里按顺序是读r、写w、执行x。所以rw-r--r--意思是属主可读写属组可读其他人可读。数值化的原因也很简单r4、w2、x1把三段权限分别加起来就是三位数字。42174004所以chmod 755 deploy.sh # 属主7可读写执行属组5读执行其他5 chmod 640 id_rsa # 属主6读写属组4只读其他无 chmod 600 .ssh/id_rsa # 只有属主能读写其他一律拒绝这里我非常想多说一句不要随手chmod 777。777等于把门敞开任何人都能改掉你的文件。尤其对于密钥、脚本、配置文件给到600或640通常已经足够。别用图省事作为理由——一个自由的环境依赖的是每个人都守住自己的边界。目录权限也需要chmod -R慎重使用递归修改很容易把不该改的也改了。通常我更推荐先ls -l看清楚再针对具体文件改而不是大范围无差别修改。3.2 root、普通用户与sudo一条需要克制使用的特权通道su和sudo是两个经常被混为一谈的命令。su是切换用户通常切到rootsudo是借用特权身份执行这一条命令默认执行者仍是当前用户身份是root。比如sudo apt update sudo systemctl restart nginx sudo -i # 进入root的shell非必要别用为什么日常不建议一直待在root里因为root操作没有任何护栏。rm -rf 在普通用户下最糟糕也就删掉自己目录里的文件在root下一个手滑可以瞬间毁掉整个系统。用sudo至少每次都有记录出问题能追溯是哪个用户哪个时间敲了哪条命令。这个可追溯性本身就是自由的一部分。我常对学员说真正的自由是知道我有权限去做但仍然选择谨慎地做。sudo不是麻烦它是给疯马配的缰绳不是限制而是让你跑得更远。3.3 umask从创建文件那一刻边界就写好了每次新建文件、新建目录系统默认给予的权限不是固定的它由umask决定。执行umask查看当前值通常输出0022。这个值表示新建文件/目录时要屏蔽掉的权限位默认文件权限是666目录是777减去umask所以新建文件通常是644目录是755。如果你希望新文件别人完全看不到就umask 077之后新建的文件默认600、目录700。我在跑Web服务的时候经常把上传目录的umask设成027这样同组合作的人可读但其他人完全不可见。umask给我最大的启发是边界不是事后再修的而是从文件诞生那一刻就写好在基因里的。Linux的浪漫始终都在这些默认动作里。4. 进程、守护与网络浪漫也要有“不轻易死掉”的韧劲有些程序需要一直跑着即使没有人盯着它。这是个关于韧劲的话题也是Linux里最难被新人理解的一块。你会发现自己变得像一个花匠不光要会种花还要知道什么时候浇水、什么时候修剪、什么情况下可以安心睡一觉。4.1 ps、top与kill看清楚谁在跑再决定让谁谢幕查进程最常用的组合是ps auxa显示所有用户、u显示详细信息、x显示没有控制终端的进程。配合grep可以快速定位ps aux | grep nginx # 会看到一列进程以及各自PID top # 动态查看CPU和内存占用找到PID之后就可以kill 1234这是发送SIGTERM信号属于礼貌地请进程退出。它给了程序保存状态、清理资源的时间。如果它不响应再考虑kill -9 1234这是SIGKILL强制杀死没有任何协商余地。我特别想强调kill -9是最后手段。它就像直接拔电源再简单粗暴不过但数据库、写入中的服务被这么一杀很可能留下损坏文件。我见过有人杀一个卡住的Python训练脚本不管三七二十一kill -9第二天才发现模型保存一半整个文件都废了。正确做法是先给进程一个缓冲时间kill等30秒实在没动静再上kill -9。4.2 nohup、systemd与journalctl让服务在你看不见的地方继续活着如果只是临时让一个脚本在退出终端后继续跑用nohupnohup ./run.sh run.log 21 是放到后台nohup是忽略挂断信号HUP这样即使关闭SSH脚本也不会跟着退出。它的定位是临时托付。更正式的做法是写一个systemd服务让系统来管理它的启停、崩溃重启和开机自启。先建一个服务文件/etc/systemd/system/myapp.service[Unit] DescriptionMy App Afternetwork.target [Service] ExecStart/home/user/app/app.py Restarton-failure Useruser [Install] WantedBymulti-user.target然后systemctl daemon-reload systemctl start myapp systemctl enable myapp systemctl status myappRestarton-failure的意思是进程崩溃时自动拉起来只要守护进程还在服务就不会轻易“死掉”。查看运行日志用journalctl -u myapp -f比大海捞针一样翻文件高效得多。把nohup比喻成临时找熟人托管systemd则更像正式领养。守护进程是真的在房间里守夜的那位——平时你看不见他但半夜服务意外退出他立刻就能把人拉回来。4.3 ss与lsof管好那些悄悄开着的端口聊到网络就绕不开端口排查。最常用的场景是启动应用时报端口被占用。这时候ss最直接ss -tlnp | grep 8080 # 输出会看到 LISTEN 0 ... *:8080 users:((java,pid9527,fd380))看到PID之后就可以决定这个进程是该保留还是该结束。老一点的系统没有ss用netstat -tlnp替代但ss更快更直观。如果你想知道某个端口被哪个进程占用也可以用lsof -i :8080。这里依然要提一句如果是数据库、缓存这类进程占据了端口别仗着端口被占用了就急着kill -9。先看看那个进程是什么、为什么还在也许它只是在等一个正在写了一半的数据。礼貌一点先用kill再观察。5. 给终端写一封情书定制一套顺手且赏心悦目的命令行环境一个人怎么用终端基本能看出他对待生活的态度。有人连终端提示符都懒得改一直黑底白字有人花半小时配一个赏心悦目的提示符每条路径都清清楚楚。我倒不觉得后者更高级但适合自己的终端确实能省下大量注意力。5.1 PS1与PROMPT_COMMAND让提示符为你说话默认的提示符通常是userhost:~$虽然够用但信息密度太低。用PS1可以自定义export PS1\[\033[01;32m\]\u\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ 这样用户名和主机名是绿色当前路径是蓝色后面的$是普通颜色。\u是用户名、\h是主机名、\w是当前路径、\$在普通用户下显示$、root下显示#。颜色码\[\033[01;32m\]看起来吓人其实只需要记住开始一个颜色用\[\033[01;32m\]恢复默认用\[\033[00m\]就够了。如果你想在提示符里显示其他信息比如git分支可以用PROMPT_COMMAND它在每次显示提示符之前执行一段命令。我一般在仓库目录里能看到当前分支省去反复敲git branch的麻烦。写入~/.bashrc之后source ~/.bashrc就永久生效。这个小改动会让你每次看到终端都更舒服一点千万别小看这种舒适感对长期效率的影响。5.2 history与快捷键让回忆变快的那些小事敲过一百遍的命令如果每次都要重新打一遍那就太亏了。Linux里history记录了你输入过的所有命令配合几个快捷键能大幅提速!!重复上一条命令比如sudo !!上一条权限不够加sudo再跑一次!$上一条命令的最后一个参数CtrlR反向搜索历史输入几个字母整条命令就回来了举个例子mkdir /tmp/long_dir cd !$ # 等价于 cd /tmp/long_dir设置历史忽略重复项能让你搜索时不那么吵闹export HISTCONTROLignoredups:erasedups export HISTSIZE10000此外还可以把会话共享打开多个终端之间共享历史。不过这是个人偏好我自己更喜欢按终端隔离避免两个项目的历史互相污染。5.3 顺手的小工具组合grep高亮、df/du、tmux与那些能节省半天的小东西终端体验的下一步是给常用命令加一点点“滤镜”。alias grepgrep --colorauto这一行让grep匹配到的关键词有颜色找日志时高亮显示关键字效率立刻不一样。再看看磁盘df -h # 人类可读的磁盘占用 du -sh * # 当前目录下每个子目录占了多少空间如果有个长任务需要挂机又担心SSH断了会话就丢用tmux。新建会话tmux new -s work中途断开重新连上服务器后tmux attach -t work就能回到原来的会话里。这种感觉就像把工作现场摆在桌上不管中途发生了什么回去继续干就是了。再往上一点装个fzf配合CtrlR就能变成交互式模糊搜索敲几个字符整个历史里相关命令都浮上来。装完Docker、Python之后再给常用命令配好别名这组小东西组合起来日常效率提升其实是肉眼可见的。6. 当浪漫遭遇意外排错思路才是真正的长期主义写了几年脚本我最大的变化不是记住的命令更多而是面对报错不再心慌。Linux的报错信息有时候很冷但它从来不是在骂你而是在指路——关键是你要懂得往哪看。6.1 从报错信息开始读日志比问人更有用出了问题第一步永远是看日志。系统服务用systemd管理时journalctl是一站式入口journalctl -xe # 查看最近的错误和相关服务日志 journalctl -u nginx -n 50 --no-pager # 只看nginx最近50行 journalctl -u myapp -f # 实时跟踪某个服务的日志不是systemd再管理的应用就去看它自己的应用日志通常都在/var/log/下。网络问题可以看dmesg输出的内核日志。实时跟踪一个文件用tail -f。有个很常见的年轻人毛病报错一弹出来就开始找同事、发截图。其实大多数报错的第一行里已经写清楚了哪个命令、哪个文件、哪个行号。最稳的排错路径是先自己读日志再自己复现最后实在没思路才去提问。提问的时候带着日志原文和操作步骤人家也愿意帮你。6.2 隔离变量二分法定位问题的通用套路排错的核心不是碰运气是隔离变量。大概流程是确认问题范围是我这台机器的问题还是所有机器都这样是配置问题还是依赖问题直接运行命令看它真正的报错是什么不要只看包装后的提示。如果脚本不执行先看文件权限ls -l script.sh没有执行权限就chmod x。如果权限没问题看解释器which bash、检查脚本第一行是否正常。用bash -x script.sh追踪每一步执行哪一步报错立刻就能看到。举一个真实场景./deploy.sh报Permission denied。这时最不应该做的就是chmod 777 deploy.sh。先ls -l deploy.sh看到权限确实是-rw-------属主是你自己那就chmod 755 deploy.sh如果属主是root就要考虑是不是该sudo chown调整归属。还有一种是Windows上编辑过的脚本在Linux里会报bad interpreter因为文件带Windows换行符或CRLF这时候用dos2unix处理一下就行。再举cron的例子任务到点了没跑。排查三步crontab -l看任务是否真的保存了查/var/log/syslog里crontab有没有执行行最后手动执行脚本bash -x /home/user/backup.sh确认脚本本身没有在新环境里缺少依赖。大多数时候问题就藏在环境变量没设置或脚本里用了alias没有生效这种细枝末节里。6.3 复盘笔记把你踩过的坑变成长期的自由最后我强烈建议每个人都要有一套自己的排错笔记。我不指望记住所有命令但我会在~/notes里建一个linux.md把每一次踩过的坑、搜索到的解法、排错链路都记下来。配合aliasalias notevim ~/notes/linux.md下次遇到同样的问题直接note打开搜索一下关键字几分钟就能解决。这个方法的价值不是让你显得勤奋而是让你的自由是可持续的——你不需要每次从零开始你的经验会像滚雪球一样累积。写在最后分享一点我个人的体会。写了这么多年脚本我越来越觉得Linux给人的自由不是漫无边际的撒野而是在理解规则之后的从容。每一条指令都是你和系统之间的一次对话当你学会了管道、脚本、权限和排错这个对话会变得越来越顺畅你甚至能在深夜盯着一条实时滚动的日志时感到一种奇异的平静。上篇我们说命令是入口下篇我想说入口后面不是迷宫而是一张可以按照自己习惯随时重新布置的桌子。去跑一遍ps aux | grep 你的用户名看看系统里都有哪些进程正在为你工作去给最常用的长命令配一个alias再去写一个属于自己的备份脚本。风吹字符起也不过是敲对了那个回车而已。
返回列表