Shell 基础、管道与引用¶
标准输入、输出与错误¶
每个命令通常有三个标准流:
command > output.txt # 覆盖 stdout
command >> output.txt # 追加 stdout
command 2> error.log # 覆盖 stderr
command > all.log 2>&1 # stdout、stderr 写入同一文件
command < input.txt # 从文件读取 stdin
重定向从左向右处理:
command >all.log 2>&1 # stderr 跟随已经指向 all.log 的 stdout
command 2>&1 >all.log # stderr 仍指终端,只有 stdout 进文件
管道¶
管道把左侧 stdout 传给右侧 stdin:
journalctl -u nginx --since today \
| grep ' 5[0-9][0-9] ' \
| awk '{print $1, $2, $3}' \
| sort \
| uniq -c \
| sort -nr
stderr 默认不会进入管道,需要明确合并:
不要写无意义的 cat file | grep pattern,直接 grep pattern file 更清楚;但 cat 合并多个文件或展示上下文时可以使用。
退出状态与条件执行¶
Shell 约定 0 表示成功,非 0 表示失败。grep 的 1 表示没有匹配,不一定是程序故障;2 才通常表示参数或读取错误。
脚本建议:
-e:未处理的失败尽早退出,但在条件表达式中有例外。-u:引用未定义变量时报错。pipefail:流水线中任一命令失败会影响整体状态。-E:ERR trap 在函数等上下文中继承。
这些选项不是自动安全保证,脚本仍要正确处理允许失败的命令和清理动作。
引号¶
| 写法 | 行为 |
|---|---|
'text $var' |
完全按字面量,不展开变量 |
"text $var" |
展开变量和命令替换,但保留整体参数 |
text\ space |
反斜杠转义下一个字符 |
| 无引号 | 变量展开后还会字段分割和通配符展开,风险最高 |
传递文件名和用户输入时始终加双引号:
-- 表示后续内容不再按选项解析,防止文件名以 - 开头时被当成参数。
命令替换与算术¶
使用 $(...),不要使用难以嵌套的反引号。命令替换会移除结尾换行,不适合无损保存任意二进制或多行数据。
常用辅助命令¶
head -n 20 file
tail -n 100 file
tail -F /var/log/app.log
wc -l file
cut -d: -f1 /etc/passwd
tr '[:lower:]' '[:upper:]'
paste file1 file2
tee output.log
tail -F 会在日志轮转后继续跟踪同名文件;tee 一边显示一边写文件。对来自 find 的文件名使用 NUL 分隔,避免空格和换行破坏: