🖥️ 第08章 · 重定向/管道/环境变量

export PATH > >> < |

重定向 / 管道 / 环境变量

这一章讲 Shell 的"连接"能力:把输出送到文件、把文件读进命令、把一个命令的结果喂给下一个命令,以及那个藏在背后的环境变量表。它是把简单命令组合成强大工具的分水岭。

标准输入输出与文件描述符

每个进程默认有三个流:

名称 文件描述符 默认去向 符号
标准输入 stdin 0 键盘 <
标准输出 stdout 1 屏幕 >
标准错误 stderr 2 屏幕 2>

重定向就是把这几个流"改道"。

输出重定向 > 与 >>

命令 > 文件      # 把标准输出写入文件(覆盖旧内容)
命令 >> 文件     # 把标准输出追加到文件末尾
echo "hello" > app.log      # 写入,覆盖
echo "world" >> app.log     # 追加到末尾

警告 > 会直接覆盖目标文件,不留备份。想保留就用 >> 追加,或先 cp 一份原文件。误用 > 覆盖系统配置是最常见的"我把配置清空了"事故。

错误重定向 2>

如果命令执行出错,报错信息走的是 stderr(2),普通 > 拦不住它。

命令 2> error.log       # 把错误信息写入 error.log
命令 > all.log 2>&1     # 把标准输出和错误都写入同一个文件
命令 > /dev/null 2>&1   # 既不看输出也不看错误(静默)

2>&1 的含义是"把 stderr(2)重定向到当前 stdout(1)已经指向的地方"。

提示 排查部署脚本时,命令 2>&1 非常重要——因为 Python/Node 报错、apt 报错都走 stderr,只重定向 > 时看不到任何错误,会误以为"成功"。

输入重定向 < 与 <<<

命令 < 文件         # 把文件内容作为命令的输入
wc -l < access.log   # 统计 input.log 行数,不走"文件参数"方式
mysql -u root <<< "SHOW DATABASES;"   # 把字符串作为输入喂给命令

<<<(Here-string)把一段文本直接作为输入传给前面的命令。<<EOF(Here-doc)则能在脚本里嵌入多行内容。

管道 |

管道是重定向的升华:把左边命令的标准输出,直接接成右边命令的标准输入。它不经过文件,数据扇贝一样流过。

命令1 | 命令2 | 命令3
ps aux | grep node        # 筛进程
cut -d: -f1 /etc/passwd | sort | wc -l   # 数用户
grep "GET" access.log | awk '{print $1}' | sort | uniq -c | sort -rn

提示 管道是"命令组合拳"的灵魂。管道链里只有最后一条命令的输出会显示到屏幕,前面的都作为"中间数据"。常见"三件套":grep 筛行 | cut/awk 提列 | sort|uniq 统计。

在这台服务器上统计 nginx 访问量:

awk '{print $9}' /var/log/nginx/access.log 2>/dev/null | sort | uniq -c

环境变量与环境变量表

环境变量是"进程启动时就带着的一组键值对",影响程序行为。它们存进 Shell 的环境变量表,并继承给所有子进程。

echo $PATH          # 查询变量,取值加 $
echo $HOME          # 家目录
printenv            # 列出所有环境变量
变量 常见含义
PATH 命令查找路径(冒号分隔)
HOME 当前用户家目录
USER/USERNAME 当前用户名
SHELL 当前 Shell 路径
LANG 语言/编码
NODE_ENV 应用运行环境(production/development)

注意 查询变量要 $ 前缀(echo $PATH);赋值时不加 $,且 = 两边不能有空格。

设置与导出环境变量 export

export NODE_ENV=production     # 设置并导出给子进程
export PATH=$PATH:/opt/custom/bin   # 追加路径

export 以外的普通赋值只在当前 Shell 生效,不传给子进程。要让 CDN/部署脚本、systemd 服务读到,往往要 export 或用 env 指定。

NODE_ENV=production node server.js   # 单次启动时临时带环境
env | grep NODE_ENV                   # 确认变量

在这台服务器上,前端应用由 systemd 托管时,环境变量写在服务的 Environment= 里(比如 NODE_ENV=production),而非常驻 export——因为 systemd 启动的进程没走你的 Shell。

环境变量持久化

要让某个变量永久生效,取决于你想影响谁:

方式 写入位置 生效范围
~/.bashrc 当前用户登录 Shell 当前用户
~/.profile 当前用户登录时 当前用户
/etc/profile 所有用户登录 全系统
/etc/environment 登录时全局 全系统
systemd Environment= 特定服务 该服务
# 以追加 PATH 为例,写进 ~/.bashrc 末尾
echo 'export PATH=$PATH:/opt/bin' >> ~/.bashrc
source ~/.bashrc          # 让修改在当前会话立即生效

警告 source 后临时生效,但要重开终端才真正落定。还有一个坑:export PATH=... 时如果不小心写错路径,可能让 shell 找不到任何命令,连 ls 都用不了。修改 PATH 前务必先备份原值。

综合实战:环境变量 + 管道

给一个 Node 服务临时设置生产模式并把输出记到日志:

NODE_ENV=production node server.js >> /var/log/app.log 2>&1
# 环境变量注入  +  追加日志  +  错误也进日志

易错点

  • > 是覆盖,>> 是追加,别用错。
  • 报错要走 2>&1,否则看不到错误。
  • = 两边不能有空格(NODE_ENV = xxx 是错的)。
  • 查询需要 $,赋值不能带 $。
  • 改 PATH 前先记下原值,以免把自己锁死。

相关命令

echo、export、unset、env、printenv、>、>>、<、|、tee(边输出到屏幕边写文件)、xargs(把管道输出当成参数交给命令)。