外观
查看与编辑文本
tail -f 和 vi 是运维使用频率最高的两条命令。前者有个日志切割后失效的坑,后者有"怎么退出"的经典问题。
一、整体查看
bash
cat -n /etc/hosts
tac /var/log/boot.log | head
wc -l /etc/nginx/nginx.conf
file /data/app.jartext
1 127.0.0.1 localhost localhost.localdomain
2 ::1 localhost localhost.localdomain
3 10.0.0.31 kafka-1
4 10.0.0.32 kafka-2
148 /etc/nginx/nginx.conf
/data/app.jar: Java archive data (JAR)cat 只适合小文件。几百 MB 的日志用 cat 会把终端卡死几十秒。
二、less:看大文件
bash
less /var/log/messages| 按键 | 作用 |
|---|---|
空格 / b | 下一页 / 上一页 |
g / G | 开头 / 结尾 |
/keyword | 向下搜索,n 下一个,N 上一个 |
?keyword | 向上搜索 |
F | 实时跟随(类似 tail -f),Ctrl+C 退出跟随 |
-S | 不折行(长行横向滚动) |
q | 退出 |
:n | 打开下一个文件(多文件时) |
less +F file 直接进入跟随模式,比 tail -f 更好的地方是可以随时 Ctrl+C 回去翻历史。
三、head / tail
bash
head -20 app.log
tail -20 app.log
tail -n +100 app.log # 从第 100 行开始到结尾
tail -c 1k app.log # 最后 1KB(按字节)
tail -f app.log # 跟随
tail -F app.log # 跟随,文件被轮转后自动重开text
2026-10-27 21:14:02 INFO health check ok
2026-10-27 21:14:07 INFO health check ok日志切割后 tail -f 会失效
logrotate 把 app.log 重命名成 app.log.1、再建一个新的 app.log 时,tail -f 仍然盯着旧 inode,你会看到日志"不再更新"。
用 tail -F(大写 F,等价于 --follow=name --retry)会自动检测文件被替换并重新打开。生产环境一律用 -F。
常用组合:
bash
# 只跟某个关键字
tail -F app.log | grep --line-buffered -i error
# 跟多个文件,带文件名前缀
tail -F app.log error.log
# 时间范围(需要日志里有时间戳)
tail -F app.log | grep '2026-10-27 21:'grep 不加 --line-buffered 时输出会被缓冲,看起来像"卡住"。管道接 grep 一定要加。
四、vi 生存指南
打开:
bash
vi /etc/nginx/nginx.conf三种模式:
text
普通模式(默认) --i / a / o--> 插入模式
^ |
| |
+------ Esc -------------------+
|
+-- : / ---> 命令/搜索模式(Esc 返回)常用操作
| 操作 | 作用 |
|---|---|
i | 光标前插入 |
a | 光标后插入 |
o | 下一行插入 |
Esc | 回到普通模式(先按这个再做别的) |
:w | 保存 |
:q | 退出(未修改时) |
:wq 或 ZZ | 保存并退出 |
:q! | 不保存强制退出(改错了用它) |
dd | 删除当前行 |
yy + p | 复制当前行 + 粘贴 |
u | 撤销 |
/keyword | 搜索,n 下一个 |
gg / G | 文件头 / 文件尾 |
:%s/old/new/g | 全文替换 |
:set nu | 显示行号 |
卡在 vi 里出不来
按 Esc,再输入 :q! 回车。如果提示 E37: No write since last change,说明有未保存修改,:q! 就是丢弃修改退出。
如果连 Esc 都没反应,可能是终端问题:按 Ctrl+C,再 Esc,再 :q!。
配置文件改之前留个备份:
bash
cp -a nginx.conf nginx.conf.$(date +%F-%H%M)
vi nginx.conf改完先验证再 reload,比如 nginx -t、sshd -t。
五、diff:改了什么
bash
diff -u nginx.conf.orig nginx.confdiff
--- nginx.conf.orig 2026-10-27 21:14:02
+++ nginx.conf 2026-10-27 21:18:41
@@ -12,7 +12,7 @@
http {
include mime.types;
default_type application/octet-stream;
- sendfile off;
+ sendfile on;
keepalive_timeout 65;
}-u 是 unified 格式,- 行是被删的,+ 行是新增的。-y 并排显示,-r 递归比较目录。
bash
diff -r /etc/nginx /data/backup/nginx-2026-10-27
vimdiff a.conf b.conf # 可视化对比六、编码与换行
bash
file -i app.conftext
app.conf: text/plain; charset=iso-8859-1bash
# 转编码
iconv -f GBK -t UTF-8 app.conf -o app.conf.utf8
# 看有没有 Windows 换行
file app.sh
cat -A app.sh | head -3text
app.sh: ASCII text, with CRLF line terminators
#!/bin/bash^M$
echo hello^M$^M 就是 CR。Shell 脚本带 CRLF 会报 bash: ./app.sh: /bin/bash^M: bad interpreter。
bash
# 去掉 CR
sed -i 's/\r$//' app.sh
# 或
dos2unix app.sh在 Windows 上编辑过的脚本
用 Notepad、VS Code 默认可能存成 CRLF。放到 Linux 上执行前先 file 看一下,或者用 dos2unix 批量处理:
bash
find /opt/app/scripts -name '*.sh' -exec dos2unix {} +七、快速查某个配置在哪
bash
grep -rn 'worker_connections' /etc/nginx/
grep -rn --include='*.conf' 'proxy_pass' /etc/nginx/text
/etc/nginx/nginx.conf:14: worker_connections 1024;-r 递归,-n 带行号。比 find | xargs grep 更直接(且不会因为文件名有空格而炸)。
八、踩过的坑
| 现象 | 根因 | 处置 |
|---|---|---|
tail -f 日志不动了 | 日志被轮转,盯的是旧 inode | 用 tail -F |
tail -f | grep 看起来卡住 | grep 输出缓冲 | grep --line-buffered |
cat 卡住几分钟 | 文件太大或二进制 | 用 less / head |
vi 里输入 :wq 没反应 | 还在插入模式 | 先 Esc |
脚本报 bad interpreter: ^M | CRLF 换行 | dos2unix |
| 改了配置不生效 | 忘了 reload | nginx -t && nginx -s reload |
diff 全是改动 | 一边文件是 CRLF | dos2unix 后再比 |