This article primarily uses Bash-style syntax. Fish differs in its syntax for variables, command substitution, history, and configuration.
The previous three articles covered "which commands to use"; this one covers "how to join them together". Pipes and redirection put the Linux philosophy into practice: small tools combine to do powerful things.
Pipes#
| — Feed one command’s output into the next command
command1 | command2The basic idea: standard output from command1 becomes standard input to command2 directly.
ps aux | grep python # ps 的输出交给 grep 筛选
ls -l | wc -l # 统计显示行数,含 total 行;不是可靠文件数
cat file.txt | grep error # 等价于 grep error file.txt
du -sh * | sort -hr # 列出文件大小,从大到小排You can keep chaining pipes:
cat access.log | grep "404" | cut -d' ' -f1 | sort | uniq -c | sort -rn
# 解释:日志 → 筛404 → 取IP列 → 排序 → 去重计数 → 按次数倒排
# 结果:谁在疯狂 404 一目了然Redirection#
> — Write output to a file (overwrite)
echo "hello" > file.txt # 写内容到文件,覆盖原有内容
ls -la > listing.txt # ls 的结果存到文件,终端不显示>> — Write output to a file (append)
echo "another line" >> file.txt # 追加到末尾< — Read input from a file
wc -l < file.txt # 把文件内容喂给 wc(等价于 wc -l file.txt)2>&1 — Merge standard error into standard output
./script.sh > output.log 2>&1 # 正常输出和报错都进同一个文件
./script.sh > /dev/null 2>&1 # 静默运行,什么都不显示A model for understanding it:
| Number | Name | Default source or destination |
|---|---|---|
| 0 | stdin (standard input) | Keyboard |
| 1 | stdout (standard output) | Terminal |
| 2 | stderr (standard error) | Terminal |
2>&1 means: redirect stderr (2) to wherever stdout (1) is currently going.
Wildcards#
* # 匹配任意多个字符
? # 匹配恰好一个字符
[abc] # 匹配 a、b、c 中的任意一个
[0-9] # 匹配 0-9 任意数字ls *.md # 所有 .md 文件
ls report_??.txt # 先预览任意两个字符后缀(不限定数字)
rm -- report_??.txt # 核对列表后才删除;不匹配时的行为取决于 Shell
ls [A-Z]*.md # 大写字母开头的 .md 文件Variables#
Definition and use
name="hello" # 定义变量,等号两边不能有空格
echo "$name" # 使用变量,加 $ 前缀
echo "${name}" # 也可以用花括号包起来Environment variables
echo $PATH # 可执行文件的搜索路径
echo $HOME # 你的家目录
echo $USER # 当前用户名
env # 列出所有环境变量
export MY_VAR="val" # 设为环境变量(子进程可见)Command substitution
now=$(date) # 把 date 命令的输出赋给变量
echo "现在时间:$now"
files=$(find . -maxdepth 1 -type f -printf 'x\n' | wc -l) # GNU find:当前目录普通文件数Aliases#
alias — Give a long command a short name
alias ll='ls -lah' # ll 代替 ls -lah
alias gs='git status' # git 常用操作缩到两字母
alias ..='cd ..' # 快速回上级
alias # 查看当前所有别名To make it persistent, put it in ~/.bashrc (bash) or ~/.config/fish/config.fish (fish).
History and shortcuts#
history — View command history
history # 全部历史
history | grep git # 在历史中搜 git 相关命令Reuse commands from history
!! # 重复上一条命令
!git # 重复最近一条以 git 开头的命令
!$ # 上一条命令的最后一个参数Terminal keyboard shortcuts
| Shortcut | Action |
|---|---|
Ctrl+C |
Terminate the current foreground program |
Ctrl+Z |
Suspend the current foreground program |
Ctrl+D |
Send EOF (exit the terminal or close the input stream) |
Ctrl+L |
Clear the screen (equivalent to clear) |
Ctrl+R |
Search command history backward |
Ctrl+A |
Move the cursor to the beginning of the line |
Ctrl+E |
Move the cursor to the end of the line |
Ctrl+W |
Delete the word before the cursor |
Ctrl+U |
Delete everything before the cursor |
Ctrl+R is particularly useful: search a long history for a command you have used, then press it again to continue searching backward.
Combination examples#
Solve practical problems with a one-line command
# 当前目录项目(含目录)的磁盘占用前 5 名
du -sh * | sort -hr | head -5
# 统计名称匹配的进程数(不是线程数)
pgrep -c nginx
# 查看已知 PID 的线程数与线程列表
ps -o nlwp= -p PID
ps -T -p PID
# 查看 8080 端口被哪个程序占了
ss -tlnp | grep 8080
# 递归找所有 .md 文件中有多少行包含 "TODO"
grep -rn --include="*.md" "TODO" . | wc -lThis is the Unix philosophy: have each command do one thing well, and connect them with pipes.
The core mental model#
输入(stdin) → [命令] → 输出(stdout)
↓
错误(stderr)
管道 | :把 A 的 stdout 给 B 的 stdin
重定向 > :把 stdout 存到文件
2>&1 :把 stderr 合并到 stdout 同一去处Once you understand this, the ways of connecting commands fall naturally into place.
Redirections are processed from left to right: > output.log 2>&1 and 2>&1 > output.log are not equivalent. History expansions such as !! are available in interactive Bash; check the expanded command before executing it.
References & further reading
Adapted from technical notes. Examples use generic names.