管道的本质:给数据流接线
$ cat access.log | grep " 500 " | awk '{print $1}' | sort | uniq -c | sort -rn | head| 把左边命令的标准输出接到右边命令的标准输入,数据像水一样流过整条线。背后的哲学一句话:每个程序只做一件事并做好它,复杂问题靠组合解决。所以 Linux 命令几乎都遵守「有输入、有输出、不问来源」的约定——cat、grep、awk、sort 这类「过滤器」天生能串。
重定向:> >> 2> 与 /dev/null
$ grep ERROR app.log > error.log # 覆盖写入(原有内容清空)
$ grep ERROR app.log >> error.log # 追加写入(保留原有内容)
$ make 2> build_err.log # 只收错误输出(2 = stderr)
$ command > all.log 2>&1 # 标准输出和错误合并进同一个文件
$ command > /dev/null 2>&1 # 全部丢弃(定时任务静默跑)1 是 stdout,2 是 stderr;2>&1 意为「把 2 接到 1 当前指向的地方」,顺序不能写反。/dev/null 是黑洞文件,写进去的东西全部蒸发——不想看的输出、不想被邮件打扰的 crontab,统统丢这里。
xargs:把输出变成参数
管道传的是「数据流」,但 rm、cp、kill 这类命令只吃「参数」。xargs 是两者之间的翻译官:
$ find . -name "*.log" | xargs rm # 找到的每个文件名变成 rm 的参数
$ cat servers.txt | xargs -n 1 ping -c 1 # 每行内容作为参数逐个执行
$ grep -rl "8080" conf/ | xargs sed -i.bak 's/8080/9090/g' # 上篇的批量替换体会差别:cat f | grep x 是数据流进 grep;ls | xargs rm 是文件名变成 rm 的参数。「命令不认管道输入」时,第一反应就是加 xargs。
tee 与子命令替换
$ ./deploy.sh | tee run.log # 边在屏幕实时显示、边写入文件
$ ./deploy.sh | tee -a run.log # -a 追加而不是覆盖
$ PORT=$(cat config.json | awk -F":" '{print $2}') # $( ) 把命令输出赋给变量
$ echo $PORTtee 在排查时极好用:既想实时盯输出,又想留一份完整档案;$( ) 则是写 shell 脚本的基石。
组合实战:三道高频题
# 1. 当前目录下哪个文件夹最占空间?
$ du -sh * | sort -rh | head
# 2. TCP 连接状态统计(有没有大量 TIME_WAIT / SYN_RECV?)
$ ss -ant | awk 'NR>1{print $1}' | sort | uniq -c
# 3. 最近登录的来源 IP 有没有陌生的?
$ last -20 | awk '{print $3}' | sort -u每一条都是「小火柴串成的火箭」——单个命令平平无奇,组合起来就是完整的排查动作。至此文本处理段收官,下一篇进入系统管理段第一篇:用户与权限,聊聊 chmod 777 为什么是事故之源。
评论 (0)