外观
文件与目录
这一节只收每天都会敲的。重点在几个容易记错的细节:ls -lh 和 ls -lht 的区别、rm -rf 之前该做什么、软链为什么建错位置。
一、看
bash
ls -lh /var/log
ls -lht /var/log | head -5
ls -la /etc/nginx
ls -ld /datatext
total 2.1G
-rw-r--r-- 1 root root 48M Oct 27 20:11 messages
-rw-r----- 1 root adm 1.2M Oct 27 20:10 syslog
drwxr-xr-x 2 root root 4.0K Oct 27 18:02 nginx
-rw-r--r-- 1 root root 48M Oct 27 21:02 app.log
-rw-r--r-- 1 root root 1.2M Oct 27 20:55 access.log
drwxr-xr-x 2 root root 4096 Oct 27 20:52 /data| 命令 | 区别 |
|---|---|
ls -lh | 人类可读大小,按名字排序 |
ls -lht | 按修改时间倒序,找最新文件必用 |
ls -lhtr | 时间正序(最老的在前) |
ls -lhS | 按大小倒序 |
ls -ld 目录 | 看目录本身,而不是目录内容 |
ls -a | 包含 . 开头的隐藏文件 |
total 是这些文件占的磁盘块数,不等于字节和(有块对齐和稀疏文件)。真实大小用 du -sh。
bash
stat /data/app.logtext
File: /data/app.log
Size: 50331648 Blocks: 98304 IO Block: 4096 regular file
Device: fd01h/64769d Inode: 1832441 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2026-10-27 21:02:11.334221000 +0800
Modify: 2026-10-27 21:01:58.112004000 +0800
Change: 2026-10-27 21:01:58.112004000 +0800Modify 是内容修改时间,Change 是元数据(权限、属主)变更时间。mtime/ctime 排障时经常被混淆。
二、建
bash
mkdir -p /data/app/{logs,config,tmp}
touch /data/app/.keep{} 是 shell 的花括号展开,等价于写三个 mkdir。-p 保证父目录不存在也不报错、目录已存在也不报错。
三、复制与移动
bash
cp -a /etc/nginx /data/backup/nginx-$(date +%F)
cp -r src/ dst/
mv a.txt b.txt
mv /data/app /data/app.old-a = -dR --preserve=all,保留权限、属主、时间戳、软链。备份配置文件必须用 -a,否则属主变成当前用户,恢复后服务起不来。
bash
# 只复制比目标新的
cp -u *.conf /etc/app/
# 复制时保留软链本身(不跟随)
cp -d link target/四、删(最危险的一条)
bash
rm -i important.conf # 删除前确认
rm -rf /data/app/tmp/*三个必须遵守的习惯
- 变量必须加引号:
rm -rf "$DIR"/而不是rm -rf $DIR/。DIR为空时后者变成rm -rf /。 rm -rf前先ls同一条路径:把rm换成ls跑一遍,看清单对不对。- 不要用
find ... -exec rm,用-delete前先-print:
bash
find /data/logs -name '*.log' -mtime +30 -print | head # 先看
find /data/logs -name '*.log' -mtime +30 -delete # 再删生产机上建议装 trash-cli,用 trash 代替 rm,误删能找回:
bash
trash-put /data/app/config
trash-list
trash-restore五、软链与硬链
bash
# 软链(symbolic link)
ln -s /opt/app/releases/20261027 /opt/app/current
ls -l /opt/app/currenttext
lrwxrwxrwx 1 root root 33 Oct 27 21:10 /opt/app/current -> /opt/app/releases/20261027| 软链 | 硬链 | |
|---|---|---|
| 跨文件系统 | 可以 | 不行 |
| 指向目录 | 可以 | 不行 |
| 源文件删除后 | 失效(红字) | 仍可用 |
| inode | 新 inode | 同一个 inode |
ls -l 显示 | l + 箭头 | 看不出区别,Links 计数增加 |
bash
# 更新软链(发布切换的标准动作)
ln -sfn /opt/app/releases/20261028 /opt/app/current-n 很关键:不加的话,如果 current 已经是指向目录的软链,ln -sf 会在目标目录里面建一个新链接(/opt/app/releases/20261027/20261028),而不是替换。
相对路径的软链会跟着变
ln -s ../data/app/logs /etc/app/logs 在 /etc/app/ 下创建链接,相对的是 /etc/app/ 而不是当前目录。跨目录建软链一律用绝对路径。
六、find 入门
bash
# 按名字(-iname 忽略大小写)
find /data -name '*.log' -type f
find /etc -iname 'nginx*'
# 按大小
find /var -type f -size +100M
find /var -type f -size -1k
# 按时间(-mtime 天,-mmin 分钟)
find /data/logs -type f -mtime +7
find /tmp -type f -mmin -30
# 按权限(找全局可写的文件)
find /var/www -type f -perm -o+w
# 组合
find /data -type f \( -name '*.log' -o -name '*.gz' \) -mtime +30
# 执行
find /data/logs -name '*.log' -mtime +30 -exec gzip {} \;
find /data/logs -name '*.log' -mtime +30 -exec gzip {} + # 一次传多个,快-exec ... \; 是每个文件执行一次,-exec ... + 是攒起来一次执行(xargs 风格)。后者快得多。
bash
# 打印详细信息(-printf 比 -ls 可控)
find /var/log -type f -size +100M -printf '%TY-%Tm-%Td %10s %p\n' | sort -rtext
2026-10-27 50331648 /var/log/messages
2026-10-26 10485760 /var/log/secure-20261026七、路径处理
bash
basename /data/app/logs/app.log # app.log
dirname /data/app/logs/app.log # /data/app/logs
realpath ./docs/../app # /current/absolute/path/app
readlink -f /opt/app/current # 解析软链到最终目标脚本里定位自身目录:
bash
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)八、踩过的坑
| 现象 | 根因 | 处置 |
|---|---|---|
rm -rf $DIR/ 删了根目录 | 变量为空 | 加引号 + set -u |
cp -r 后权限/属主变了 | 没用 -a | 用 cp -a |
| 软链建到了目标目录里面 | ln -sfn 少了 -n | 加 -n |
| 软链失效(红字) | 绝对路径写错,或源被删 | readlink -f 查真实指向 |
find -name 找不到明明存在的文件 | 没加引号,shell 先展开了通配符 | -name '*.log' 必须带引号 |
ls -l 目录大小只有 4096 | 目录项本身的大小,不是内容 | 用 du -sh |
mv 跨文件系统很慢 | 实际是复制+删除 | 正常,或先 tar 打包 |