Skip to content

文件与目录 ​

这一节只收每天都会敲的。重点在几个容易记错的细节:ls -lh 和 ls -lht 的区别、rm -rf 之前该做什么、软链为什么建错位置。

一、看 ​

bash
ls -lh /var/log
ls -lht /var/log | head -5
ls -la /etc/nginx
ls -ld /data
text
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.log
text
  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 +0800

Modify 是内容修改时间,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/*

三个必须遵守的习惯

  1. 变量必须加引号:rm -rf "$DIR"/ 而不是 rm -rf $DIR/。DIR 为空时后者变成 rm -rf /。
  2. rm -rf 前先 ls 同一条路径:把 rm 换成 ls 跑一遍,看清单对不对。
  3. 不要用 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/current
text
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 -r
text
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 打包