6.1 目录与路径

6.1.1 相对/绝对路径的选择原则

场景用哪种原因
写 shell script绝对路径无论在哪执行都不出错
日常操作相对路径打字少;软件在不同机器上安装路径不同时也能用
工作调度(cron/at)绝对路径执行环境不固定,相对路径会跑偏

6.1.2 目录操作指令

特殊目录符号

符号含义
.当前目录
..上一层目录
-前一个工作目录(cd - 切回去)
~当前用户主文件夹
~accountaccount 这个用户的主文件夹

💡 根目录 /.. 就是 / 自己——ls -al / 可以看到 ... 权限属性完全一致。

四个目录操作指令:

指令用途关键参数
cd变换目录cd ~ / cd 回家;cd - 回上一个;cd .. 回上层
pwd显示当前目录-P:显示真实路径而非链接路径
mkdir创建目录-p:递归创建多层;-m 711:直接指定权限
rmdir删除空目录-p:连上层空目录一起删

pwd -P 的实际用途:/var/mail 是个符号链接指向 /var/spool/mail,普通 pwd 显示 /var/mail,加 -P 才显示真实物理路径。

6.1.3 环境变量 $PATH——为什么任何地方都能执行 ls

echo $PATH
# /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

系统按 PATH 中目录的顺序搜寻同名可执行文件,找到第一个就执行。

五个核心认知:

  1. 不同身份默认 PATH 不同(root 有 /sbin 系列,普通用户没有)
  2. PATH 可以修改:PATH="${PATH}:/root"
  3. 用绝对/相对路径执行比靠 PATH 更准确
  4. 指令应该放到正确目录下
  5. .(本目录)绝不应该加入 PATH——安全风险:坏人在 /tmp 放一个叫 ls 的木马,root 进了 /tmp 执行 ls 就中招

6.2 文件与目录管理

6.2.1 ls 的常用选项

前面章节已经用过很多,这里集中列出最有用的:

选项用途场景
-l长格式(权限/拥有者/时间…)最常用,ll = ls -l
-a含隐藏文件看配置
-d只看目录本身不看内容检查目录权限
-h人类可读大小(KB/MB/GB)配合 -l
-i显示 inode 号码第七章会用
-R递归列出子目录看整个目录树
-S按大小排序谁在吃磁盘
-t按时间排序最近改了什么
-r反向排序配合 -t 看最旧文件
--full-time完整年月日时分只看年份不够时
-F文件名后加后缀标记(`*/=>@`)
--time=atime/ctime看 access 或 status 时间排查问题

6.2.2 复制/删除/移动:cp, rm, mv

cp(复制) 的核心行为:

  • 默认 cp 后拥有者变成操作者自己,时间也更新
  • 备份用 -a(= -dr --preserve=all):完整保留权限/拥有者/时间
  • 复制目录加 -r,但用 -a 更好(属性不会变)
  • -i:覆盖前询问;-u:目标文件更旧才覆盖(增量备份)
  • -s:创建符号链接(捷径),-l:创建硬链接(下一章讲)
  • -d:复制链接文件本身而非它指向的真实文件
cp ~/.bashrc /tmp/bashrc        # 简单复制,拥有者变成 root
cp -a /var/log/wtmp /tmp/       # 完整备份,属性一丝不变
cp -r /etc/ /tmp/               # 递回复制整个目录
cp -s bashrc bashrc_slink       # 创建符号链接
cp -u ~/.bashrc /tmp/bashrc     # 来源更新时才覆盖

💡 复制别人的文件想送给第三方:cp 后拥有者还是自己,需要再 chown 给对方,否则对方改不了。

rm(删除)——最危险的指令:

rm -i file          # 询问后删除(CentOS 默认 root 加了 -i)
rm -r /tmp/etc/     # 递回删除目录(非常危险!)
\rm -r /tmp/etc     # 前面加 \ 跳过 alias,不询问直接删!
rm ./-aaa-          # 删除以 - 开头的文件,必须前面加 ./
  • rmdir 只能删空目录,安全但不实用
  • rm -rf / 是著名的自毁指令,绝对不要试
  • 文件名以 - 开头时,必须用 ./-filenamerm -- -filename

mv(移动/更名)——同一文件系统内只是改目录条目,几乎瞬间完成:

mv bashrc mvtest/       # 移动到目录
mv mvtest mvtest2       # 更名!(Linux 没有 rename 指令做单文件改名)
mv f1 f2 f3 dir/        # 多个文件移到同一目录

6.2.3 basename 与 dirname

basename /etc/sysconfig/network   # → network
dirname /etc/sysconfig/network    # → /etc/sysconfig

主要用于 shell script 中提取路径的各个部分。

6.3 文件内容查阅

6.3.1 一次性显示:cat / tac / nl

指令功能关键选项
cat从第一行开始输出-n 含空白行加行号;-b 空白行不加行号;-A 显示所有隐藏字符($=换行, ^I=Tab)
tac从最后一行开始输出cat 倒过来写
nl加行号输出-b a 空白也编号;-n rz 行号前面补 0;-w 3 行号占 3 位

6.3.2 翻页查看:more / less

功能moreless(更好用)
向下翻页空格空格 / PageDown
向上翻页不支持PageUp / b
向下搜索/关键词/关键词
向上搜索不支持?关键词
跳到第一行不支持g
跳到最后一行不支持G
退出qq

💡 man page 的浏览界面就是调用的 less——所以学 less 等于学 man 的操作。

6.3.3 数据撷取:head / tail

head -n 20 file        # 前 20 行(默认 10 行)
head -n -100 file      # 除了最后 100 行,其余全输出
tail -n 20 file        # 最后 20 行
tail -n +100 file      # 从第 100 行开始到末尾
tail -f /var/log/messages   # 持续监控,新内容实时显示(Ctrl+C 停止)

经典组合——取第 11~20 行

head -n 20 file | tail -n 10        # 先拿前 20 行,再取后 10 行
cat -n file | head -n 20 | tail -n 10  # 顺便带行号

|管线(pipe):前面指令的输出交给后面指令继续处理,而不是输出到屏幕。

6.3.4 读二进制文件:od

od -t c /usr/bin/passwd     # 以 ASCII 字符显示二进制内容
od -t oCc /etc/issue        # 同时显示八进制数值和 ASCII 字符
echo password | od -t oCc    # 查 "password" 每个字母的 ASCII 码

最左边一列是八进制的字节偏移量(0000020 = 第 16 个 byte = 2×8)。

6.3.5 修改时间或创建空文件:touch

Linux 文件有三个时间:

时间全称何时更新
mtimemodification time文件内容被修改(ls -l 默认显示的)
ctimestatus time文件状态被改变(权限、拥有者变更)
atimeaccess time文件内容被读取(cat 也会更新它)
touch file           # 文件存在→三个时间全更新为现在;不存在→创建空文件
touch -d "2 days ago" file  # 修改 mtime 和 atime,但不改 ctime
touch -t 201406150202 file  # 精确设置到 YYYYMMDDhhmm

💡 cp -a 可以复制 mtime 和 atime,但 ctime 永远无法复制——因为”复制”这个动作本身就是一次状态变更。

6.4 文件默认权限与隐藏权限

6.4.1 umask——新建文件/目录的默认权限

umask 是指”默认要拿掉的权限”,不是默认权限本身。

文件目录
最大默认-rw-rw-rw-(666,文件天生没有 x)drwxrwxrwx(777)
root 的 umask=022666 - 022 = 644(rw-r—r—)777 - 022 = 755(rwxr-xr-x)
普通用户 umask=002666 - 002 = 664(rw-rw-r—)777 - 002 = 775(rwxrwxr-x)
umask       # 查看数字 → 0022(只看后三位 022)
umask -S    # 查看符号 → u=rwx,g=rx,o=rx
umask 002   # 修改为 002(同群组也能写)

💡 用减法算 umask 是错误的:666-003=663 但实际是 -rw-rw-r--(664)。因为 x 在文件上是直接被 umask 拿掉的,不能”加回来”。正确理解是”默认值减去 umask 中每个位置上对应的权限位”。

umask 的团队协作意义:如果团队共用目录,umask 002 让群组成员可以互相编辑对方新建的文件;umask 022 则只有创建者自己能写。

6.4.2 文件隐藏属性:chattr / lsattr

仅在 Ext2/Ext3/Ext4 下完整生效,xfs 只部分支持

属性效果使用场景
+i文件完全不可变:不能删/改名/修改/写(root 也不行!)保护关键配置不被误改
+a只能追加数据,不能删/改已有内容日志文件防篡改
+A不更新 atime减少磁盘 I/O
+S同步写入硬盘数据安全
chattr +i /etc/shadow      # 连 root 都删不掉
chattr -i /etc/shadow      # 解除
lsattr /etc/shadow          # 查看隐藏属性 → ----i-----------

6.4.3 特殊权限:SUID / SGID / SBIT

ls -l /usr/bin/passwd-rw**s**r-xr-x(注意那个 s)
ls -ld /tmpdrwxrwxrw**t**(注意那个 t)

权限位置数字作用对象效果
SUIDowner 的 x 位→s4二进制程序执行时获得文件拥有者的权限
SGIDgroup 的 x 位→s2二进制程序/目录执行时获得文件所属群组的权限;目录下新建文件的群组继承目录群组
SBITothers 的 x 位→t1目录只有创建者和 root 才能删除自己的文件

SUID 的经典案例——为什么普通用户能改自己的密码

  1. /usr/bin/passwd 有 SUID,拥有者是 root
  2. dmtsai 执行 passwd 时,暂时获得 root 权限
  3. 所以能写 /etc/shadow(权限 000,只有 root 能改)
  4. 但 dmtsai 直接 cat /etc/shadow 就不行——cat 没有 SUID

SGID 对目录的团队协作价值:设了 SGID 的目录,任何人在里面新建的文件,群组都跟着目录走,而不是创建者的默认群组——完美解决多人共享目录的权限问题。

SBIT 的典型应用——/tmp:任何人都能创建文件,但只能删自己的。

设置方法(在前面加第四位数字):

chmod 4755 file   # SUID → -rwsr-xr-x
chmod 2755 dir    # SGID → drwxr-sr-x
chmod 1755 dir    # SBIT → drwxr-xr-t
chmod 7666 file   # 空的 SUID/SGID/SBIT → -rwSrwSrwT(大写表示底下没 x)

💡 大小写 S/T 的含义s/t = x 权限 + 特殊权限;S/T = 该位原本就没有 x,特殊权限是”空”的——文件拥有者自己都执行不了,哪来的权限借给别人?

符号法:u+s(SUID)、g+s(SGID)、o+t(SBIT)。

6.4.4 file——判断文件类型

file ~/.bashrc          # → ASCII text
file /usr/bin/passwd    # → setuid ELF 64-bit LSB shared object ...
file /var/lib/mlocate/mlocate.db  # → data

6.5 指令与文件的搜寻

搜寻优先级which/type(查指令) → whereis(查特定目录) → locate(查数据库) → find(全盘搜索,最慢最后用)

6.5.1 找指令:which / type

which ifconfig   # /sbin/ifconfig
which -a which   # 列出所有同名可执行文件
which history    # 找不到!因为 history 是 bash 内置指令,不在 PATH 目录里

type 能区分内置指令和外部指令(后面 bash 章节会讲)。

6.5.2 找文件:whereis / locate / find

指令速度原理限制
whereis极快只搜几个特定目录(/bin, /sbin, /usr/share/man…)搜不到不在这几个目录里的文件
locate很快查数据库 /var/lib/mlocate/mlocate.db新文件还没入数据库时搜不到,要先 updatedb
find直接扫硬盘最强大,什么都能找

locate

locate -l 5 passwd       # 只显示前 5 条结果
locate -S                 # 查看数据库统计信息
updatedb                  # 手动更新数据库(读硬盘,要几分钟)

find——王牌指令,按条件搜:

# 按时间
find / -mtime 0          # 24小时内修改过的文件
find /var -mtime -4      # 4天内修改过的
find /var -mtime +4      # 4天前修改过的(不含4天本身)
find /etc -newer /etc/passwd  # 比 passwd 更新的文件
 
# 按使用者
find /home -user dmtsai  # 属于 dmtsai 的所有文件
find / -nouser            # 拥有者不存在于 /etc/passwd 的"无主"文件
 
# 按名称/大小/类型
find / -name "*.conf"    # 文件名匹配
find / -size +50k         # 大于 50KB 的文件
find / -type f            # 只找正规文件(d=目录, l=链接)

💡 -mtime n 的 “n” 含义:(见书图 6.5.1)-mtime 4 = 距今 45 天前那 24 小时内;-mtime -4 = 距今 04 天内;-mtime +4 = 距今 5 天前及更早。

关键命令

命令用途最常用选项
cd变换目录cd ~, cd -, cd ..
pwd -P显示当前真实路径-P 显示物理路径非链接路径
mkdir -p创建目录-p 递归;-m 711 设权限
rmdir -p删除空目录-p 连上层空目录一起删
ls -al列出文件属性-l 长格式;-a 含隐藏;-h 人类可读
cp -a复制(完整保留属性)-a 全保留;-r 递回;-i 询问;-u 增量
rm -rf删除(极其危险)-r 递回;-f 强制;-i 询问
mv移动/更名-u 更新;-i 询问覆盖
basename取文件名basename /a/b/cc
dirname取目录名dirname /a/b/c/a/b
cat -n显示文件内容-n 行号;-A 显示隐藏字符
tac反向显示最后一行先出
nl加行号输出-b a 全编号;-n rz 补 0
more / less翻页查看less 可前后翻+搜索
head -n N取前 N 行-n -100 跳过最后 100 行
tail -n N / tail -f取后 N 行 / 实时监控-f 实时跟踪日志
od -t c读二进制文件-t oCc 八进制+ASCII 对照
touch创建空文件/更新时间戳-d "2 days ago"-t YYYYMMDDhhmm
umask查看/设默认权限umask 002umask -S
chattr +i / lsattr设置/查看隐藏属性+i 不可变;+a 只可追加
chmod 4755设 SUID4=SUID, 2=SGID, 1=SBIT
file判断文件类型区分 ASCII/binary/data
which找可执行文件路径-a 列出所有
whereis找特定目录下文件-b 只找 binary;-m 只找 man
locate数据库搜文件名-i 忽略大小写;先 updatedb
find全盘条件搜索-mtime, -user, -name, -size, -type