第6章:文件与目录操作

第六章:文件与目录操作

6.1 ls 查看文件

ls 是 Linux 中最最最常用的命令,没有之一!它的作用是列出目录内容。就像 Windows 里的"打开文件夹看里面有啥",只不过你需要敲字儿。

6.1.1 ls:基本用法

1
2
3
4
5
# 最简单的用法,不带任何选项
ls

# 效果:列出当前目录的文件和文件夹(不含隐藏文件)
# documents  downloads  music  pictures  videos

等等,为啥我的文件和Windows长得不一样?没有 .exe 后缀?没有文件夹图标?别慌,这就是 Linux!文件名就是文件名,后缀只是习惯,不强制。

6.1.2 ls -l:详细信息

1
2
3
4
5
6
7
8
9
# -l 表示 long format,详细列表
ls -l

# 输出示例:
# total 48
# drwxr-xr-x  2 user user 4096 Jan 15 10:30 documents
# -rw-r--r--  1 user user  8192 Jan 15 09:00 notes.txt
# drwxr-xr-x  3 user user 4096 Jan 15 10:30 pictures
# -rwxr-xr-x  1 user user 16384 Jan 15 08:00 script.sh

让我来解释一下每个字段(以第一行为例):

drwxr-xr-x  2 user user 4096 Jan 15 10:30 documents
字段含义本例值
drwxr-xr-x文件类型和权限d = 目录,rwxr-xr-x = 所有者可读写执行,组可读执行,其他人可读执行
2硬链接数2
user文件所有者user
user所属组user
4096文件大小(字节)4096(4KB)
Jan 15 10:30最后修改时间1月15日 10:30
documents文件名documents

小技巧:看到 - 开头的是普通文件,看到 d 开头的是目录(directory)。这就像是文件的"身份证",一眼就能区分!

6.1.3 ls -a:显示隐藏文件

在 Linux 里,以点(.)开头的文件是隐藏文件!就像哈利·波特的隐身斗篷,平时看不见,但它们确实存在。

1
2
3
4
5
# -a = all,显示所有文件(包括隐藏的)
ls -a

# 输出:
# .  ..  .bashrc  .profile  documents  downloads  notes.txt

解释一下:

  • . = 当前目录(current directory)
  • .. = 上级目录(parent directory)
  • .bashrc = Bash 的配置文件(隐藏的)
  • .profile = 用户环境配置(隐藏的)

隐藏文件通常是用来配置的,一般不要乱动,否则系统可能抽风!

6.1.4 ls -lh:人性化大小

ls -l 显示的文件大小是字节为单位,数字看起来很别扭。-h(human-readable)会让你看得更舒服:

1
2
3
4
5
6
7
ls -lh

# 输出:
# total 48K
# drwxr-xr-x  2 user user 4.0K Jan 15 10:30 documents
# -rw-r--r--  1 user user 8.0K Jan 15 09:00 notes.txt
# drwxr-xr-x  3 user user 4.0K Jan 15 10:30 pictures

4.0K、8.0K、4.0K 是不是比 4096、8192 好看多了?这才叫人性化!

6.1.5 ls -R:递归显示

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# -R = Recursive,递归显示所有子目录
ls -R

# 输出类似:
# .:
# documents  downloads  pictures

# ./documents:
# file1.txt  file2.txt

# ./downloads:
# music  videos

# ./downloads/music:
# song1.mp3  song2.mp3

这个命令会把你目录下的所有层级都展示出来,就像一棵树!适合在你需要了解整个项目结构时使用。

6.1.6 ls -S:按大小排序

想看看哪个文件最大?-S 按文件大小排序(从大到小):

1
2
3
4
5
6
ls -lhS

# 假设输出:
# -rw-r--r--  1 user user 500M Jan 15 09:00 movie.mp4
# -rw-r--r--  1 user user 200M Jan 15 10:00 photo.zip
# -rw-r--r--  1 user user  50M Jan 15 11:00 document.pdf

小技巧:想从小到大排序?加个 -r(reverse):

1
ls -lhSr  # 从小到大

6.1.7 ls -t:按时间排序

想看最近修改的文件?-t 按修改时间排序(最新的在前面):

1
2
3
4
5
6
ls -lt

# 输出(最新的在最上面):
# drwxr-xr-x  3 user user 4096 Jan 15 14:00 downloads
# -rw-r--r--  1 user user 8192 Jan 15 13:30 notes.txt
# drwxr-xr-x  2 user user 4096 Jan 15 10:30 documents

这个命令超实用!当你忘记刚才改了什么文件时,一眼就能看到最近操作的文件。

6.1.8 ls -1:单列显示

1
2
3
4
5
6
7
8
9
# -1(数字1)单列显示,每行一个文件
ls -1

# 输出:
# documents
# downloads
# music
# notes.txt
# pictures

这个适合在脚本里处理输出时使用,parse起来更容易!


6.2 通配符

通配符(Wildcard)是 Shell 的神器!它能让你用特殊符号匹配多个文件,不用一个一个写文件名。想象一下,你要删除所有 .log 文件,难道要写一万遍 rm file1.log file2.log ...?不存在的!

6.2.1 *:匹配任意字符

星号(* 匹配任意长度、任意内容的字符串。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 列出所有 .txt 文件
ls *.txt
# 等价于 ls a.txt b.txt c.txt ...

# 列出所有以 doc 开头的文件
ls doc*
# 匹配:doc.txt, document.pdf, doc_homework.md ...

# 列出所有文件(等价于 ls)
ls *

记忆方法:* 就像万能钥匙,能打开任何锁!

6.2.2 ?:匹配单个字符

问号(? 匹配恰好一个字符

1
2
3
4
5
6
7
8
# 匹配 a.txt, b.txt, c.txt ... 但不匹配 ab.txt
ls ?.txt

# 匹配 file1.txt, file2.txt ... 不匹配 file10.txt
ls file?.txt

# 匹配 a.txt, 1.txt, x.txt(任意单字符)
ls ?.txt

⚠️ 注意?.txt 只能匹配一个字符的文件名,比如 a.txt1.txt。它不能匹配 12.txtabc.txt!想要匹配多个字符,得用 *.txt

记忆方法:? 就像占位符,一个问号占一个字符的位置。

6.2.3 []:匹配范围内字符

方括号([] 匹配方括号内的任意一个字符

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 匹配 a.txt, b.txt, c.txt
ls [abc].txt

# 匹配数字1-5
ls file[1-5].txt
# 等价于 ls file1.txt file2.txt file3.txt file4.txt file5.txt

# 匹配所有小写字母开头
ls [a-z]*.txt

# 匹配所有大写字母开头
ls [A-Z]*.txt

小技巧:方括号里可以用 - 表示范围,非常方便!

graph TD
    A["通配符选择"] --> B["* 任意字符"]
    A --> C["? 单个字符"]
    A --> D["[] 范围内字符"]
    B --> E["*.log → 所有.log文件"]
    C --> F["?.txt → a.txt, b.txt"]
    D --> G["[0-9] → 任意数字"]

6.2.4 {}:生成序列

大括号({} 不会匹配已存在的文件,而是生成序列

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 生成序列
echo {1..5}
# 输出:1 2 3 4 5

# 创建多个文件
touch file{1..3}.txt
# 创建:file1.txt, file2.txt, file3.txt

# 批量重命名(大括号扩展的经典用法)
mv document{,.bak}
# 展开为:mv document document.bak
# 原理:{,bak} 生成两个字符串 "" 和 ".bak",拼在 document 后面

💡 大括号扩展原理{,bak} 会生成两个值:空字符串和".bak"。所以 document{,.bak} 展开后变成 documentdocument.bak,正好作为 mv 的源和目标!

趣闻:{} 就像是"展开卡",写进去什么就展开成什么。和 [] 不同,[] 是匹配,{} 是生成!


6.3 pwd 显示当前工作目录

pwd = Print Working Directory,打印当前工作目录。简单说就是:告诉我,我现在在哪?

1
2
3
4
5
6
7
8
9
# 查看当前完整路径
pwd

# 输出示例:
# /home/username/documents/projects

# 在家目录执行:
pwd
# 输出:/home/username

经常有人问:“我跑这个命令的时候,当前目录是哪儿啊?"——pwd 一敲,清晰明了!

1
2
3
4
# pwd 还有一个选项
pwd -P
# -P 显示物理路径(不显示符号链接)
# 如果当前目录是一个符号链接,pwd 会显示链接路径,pwd -P 显示真实路径

6.4 cd 切换目录

cd = Change Directory,切换目录。这是 Linux 里你使用频率最高的命令之一,仅次于 ls

6.4.1 cd /:切换到根目录

1
2
3
4
5
6
# / 是 Linux 的根目录,所有文件的起点
cd /

# 查看根目录内容
ls
# 输出:bin  boot  dev  etc  home  lib  media  mnt  opt  proc  root  run  srv  sys  tmp  usr  var

根目录是 Linux 文件系统的最顶端,就像一棵大树的根。从这里出发,你可以到达任何地方!

6.4.2 cd ~:切换到用户家目录

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# ~ 代表当前用户的家目录
cd ~

# 验证一下
pwd
# 输出:/home/username

# 也可以简写(什么都不加)
cd

# cd 和 cd ~ 效果一样,都是回家!

6.4.3 cd -:返回上次目录

1
2
3
4
5
6
7
8
9
# 你在 /home/username/documents
cd /var/log

# 现在在 /var/log,突然想回刚才的目录
cd -

# 瞬间回到 /home/username/documents
# 而且会显示你去了哪儿:
# /home/username/documents

后悔药!再也不怕回不去上一个目录了!这个 - 就像是浏览器的"后退"按钮!

6.4.4 cd ..:返回上级目录

1
2
3
4
5
6
7
8
# 假设你在 /home/username/documents
cd ..

# 回到 /home/username
pwd
# 输出:/home/username

# .. 永远代表上级目录

小技巧:想连续返回两级?没问题!

1
cd ../..  # 返回上两级

6.4.5 cd ../..:返回上两级

1
2
3
4
5
6
# 从 /home/username/documents/projects 出发
cd ../..

# 现在在 /home/username
pwd
# 输出:/home/username
graph TD
    A["/home/username/documents/projects"] --> B[".. → documents"]
    A --> C["../.. → username"]
    A --> D["../../.. → home"]
    A --> E["../../../.. → /"]

6.5 mkdir 创建目录

mkdir = Make DIRectory,创建目录(文件夹)。

6.5.1 mkdir 目录名:创建单个目录

1
2
3
4
5
6
# 在当前目录下创建名为 "projects" 的目录
mkdir projects

# 验证
ls
# 可以看到 projects/ 已创建

6.5.2 mkdir -p 目录/子目录:递归创建

如果目录已经存在,mkdir 会报错。加 -p(parents)可以递归创建,即父目录不存在时一并创建:

1
2
3
4
5
6
7
8
9
# 递归创建 nested/directories/structure
mkdir -p nested/directories/structure

# 效果:
# nested/
# └── directories/
#     └── structure/

# 即使 nested 和 directories 都不存在,也会一并创建

这个 -p 是救命选项!想象一下你要创建 /home/username/projects/my-awesome-app/src/components,一层层创建得多麻烦,加个 -p 一步到位!

6.5.3 mkdir -v:显示创建过程

-v(verbose)会显示创建每个目录时的信息:

1
2
3
4
5
6
mkdir -v projects documents downloads

# 输出:
# mkdir: created directory 'projects'
# mkdir: created directory 'documents'
# mkdir: created directory 'downloads'

小技巧:-v 在脚本里特别有用,能让你知道命令到底干了什么。


6.6 touch 创建空文件

touch 的本意是"触碰”,但它最常用的功能是创建空文件

6.6.1 touch 文件名:创建空文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 创建一个空的 README.txt
touch README.txt

# 创建多个文件
touch file1.txt file2.txt file3.txt

# 验证
ls -l README.txt
# -rw-r--r--  1 user user    0 Jan 15 12:00 README.txt
# 注意大小是 0,说明是空文件

有趣的是,如果文件已存在,touch 不会清空它,而是更新文件的修改时间!这有时候很有用,比如你想让 Makefile 重新编译某些文件。

6.6.2 touch -d 日期:修改时间

1
2
3
4
5
6
# 设置文件的修改时间为指定日期
touch -d "2024-01-01 00:00" file.txt

# 查看
ls -l file.txt
# -rw-r--r--  1 user user    0 Jan  1 00:00 file.txt

小技巧:-d 选项可以设置文件的访问时间和修改时间为指定日期,这在某些场景下很有用,比如让备份文件保持原始时间戳,或者测试脚本中模拟特定时间的文件。


6.7 cp 复制文件

cp = Copy,复制文件。谁没有过"这个文件很重要,先备份一份"的时候呢?

6.7.1 cp 源 目标:基本复制

1
2
3
4
5
6
# 把 file.txt 复制一份,起名叫 file_backup.txt
cp file.txt file_backup.txt

# 把 /home/username/documents/file.txt 复制到当前目录
cp /home/username/documents/file.txt .
# 那个点 . 代表当前目录!

6.7.2 cp -r 目录 目标:递归复制

复制目录需要 -r(recursive)选项,否则会报错:

1
2
3
4
# 复制整个目录及其内容
cp -r projects/ projects_backup/

# 如果目标目录不存在,会自动创建

6.7.3 cp -i:覆盖前询问

1
2
3
4
5
6
# -i = interactive,强制询问是否覆盖
cp -i file.txt file_backup.txt

# 输出:
# cp: overwrite 'file_backup.txt'? y
# 输入 y 确认,n 取消

推荐把 cp -i 设成别名(alias),这样默认就会询问,避免误覆盖!

6.7.4 cp -v:显示过程

1
2
3
4
5
# -v = verbose,显示复制详情
cp -v document.pdf /tmp/

# 输出:
# 'document.pdf' -> '/tmp/document.pdf'

6.7.5 cp -p:保留属性

1
2
3
4
5
# -p = preserve,保留文件的属性(时间戳、权限等)
cp -p important.txt backup/important.txt

# 不加 -p:备份文件的时间会变成当前时间
# 加 -p:备份文件保持原样

小技巧:-a(archive)选项相当于 -dr --preserve=all,保留所有属性,非常适合备份!


6.8 mv 移动和重命名

mv = Move,既能移动文件,也能重命名文件(本质上是移动到新名字)。

6.8.1 mv 源 目标:移动

1
2
3
4
5
# 把 file.txt 从当前目录移动到 /tmp/
mv file.txt /tmp/

# 把 file.txt 从 /home/username 移动到 /home/username/documents/
mv /home/username/file.txt /home/username/documents/

6.8.2 mv 旧名 新名:重命名

1
2
3
4
# 重命名 oldname.txt 为 newname.txt
mv oldname.txt newname.txt

# 效果:文件还是那个文件,内容没变,就是名字变了

6.8.3 mv -i:覆盖前询问

cp 一样,mv 也有 -i 选项:

1
2
3
4
mv -i important.txt /tmp/

# 如果 /tmp/ 下已有同名文件:
# mv: overwrite '/tmp/important.txt'? y
graph LR
    A["mv 命令"] --> B["同一目录 → 重命名"]
    A --> C["不同目录 → 移动"]
    B --> D["mv a.txt b.txt"]
    C --> E["mv a.txt /path/to/b.txt"]

6.9 rm 删除文件

rm = Remove,删除文件。这是一个危险的命令,因为 Linux 没有"回收站",删了就是删了!

6.9.1 rm 文件:删除文件

1
2
3
4
5
# 删除单个文件(会询问确认)
rm file.txt

# 直接删除(如果已设置别名 rm='rm -i')
rm file.txt

6.9.2 rm -r 目录:递归删除

1
2
3
4
5
# -r = recursive,递归删除目录及其所有内容
rm -r projects/

# 删除空目录也可以用 rmdir
rmdir projects/

6.9.3 rm -f:强制删除

1
2
3
4
5
# -f = force,强制删除,不询问
rm -f file.txt

# 组合使用:强制递归删除
rm -rf projects/

6.9.4 rm -rf /:危险命令(不要执行!)

这是一个段子级别的危险命令rm -rf / 意味着"强制递归删除根目录下的所有文件"——相当于砸掉你的整个 Linux 系统!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 绝对不要执行!!!
rm -rf /

# 现代 Linux 系统默认带有 --preserve-root 保护:
rm -rf /
# 输出:rm: it is dangerous to operate recursively on '/'
#       rm: you sure you want to continue? (yes/no)

# 必须加上 --no-preserve-root 才能执行(但永远不要这么做!)
rm -rf / --no-preserve-root

# 还有这些变体,也别玩:
rm -rf /*
rm -rf / --no-preserve-root

🚨 真实案例:某程序员在服务器上执行了 rm -rf /tmp 清理临时文件,结果手抖多打了一个空格变成了 rm -rf / tmp,系统瞬间爆炸…这个故事告诉我们:输入命令前多看一眼,核对三遍再回车!

😱 另一个恐怖故事:有新手想删除当前目录下的所有文件,于是输入 rm -rf *,结果键盘上的 * 键和 / 键太近了…你懂的。所以有人建议,执行危险命令前先 pwd 确认一下自己在哪,或者干脆先 ls 看看要删的是啥!

💡 保命口诀

  • 删文件前,先 ls 看看
  • rm -rf 时,手不要抖
  • 看到 rm -rf /,赶紧 Ctrl+C
  • 定期备份,以防万一

6.10 危险的 rm -rf /:如何避免致命错误

6.10.1 使用别名保护:alias rm=‘rm -i’

.bashrc 里添加别名,让 rm 默认带上 -i(询问确认):

1
2
3
4
5
6
7
8
# 编辑 ~/.bashrc
nano ~/.bashrc

# 添加这一行:
alias rm='rm -i'

# 让别名生效
source ~/.bashrc

设置别名后,每次删除都会询问确认,多了一道安全锁!

6.10.2 使用 trash 替代 rm

有人开发了 trash-cli 工具,把文件扔进"回收站"而不是直接删除:

1
2
3
4
5
6
7
8
# Ubuntu 安装
sudo apt install trash-cli

# 使用方法
trash-put file.txt    # 删除到回收站
trash-list            # 查看回收站内容
trash-restore file.txt  # 恢复文件
trash-empty           # 清空回收站

如果你是那种经常"误删"的人,这个工具绝对是救星!


6.11 实战练习:组织你的文件结构

6.11.1 创建项目目录

让我们来实操一下,创建一个项目目录结构:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 创建项目主目录
mkdir -p my_project/{src,docs,tests,config}

# 效果:
# my_project/
# ├── src/
# ├── docs/
# ├── tests/
# └── config/

# 详细解释:
# mkdir -p = 递归创建目录(父目录不存在时自动创建)
# {} = 在一次命令中创建多个子目录

6.11.2 移动和整理文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 创建一些测试文件
touch my_project/src/main.py
touch my_project/src/utils.py
touch my_project/docs/README.md
touch my_project/tests/test_main.py

# 查看最终结构
tree my_project
# (如果系统没有 tree,用 sudo apt install tree 安装)

# 输出:
# my_project/
# ├── config/
# ├── docs/
# │   └── README.md
# ├── src/
# │   ├── main.py
# │   └── utils.py
# └── tests/
#     └── test_main.py
graph TD
    A["my_project/"] --> B["src/"]
    A --> C["docs/"]
    A --> D["tests/"]
    A --> E["config/"]
    B --> F["main.py"]
    B --> G["utils.py"]
    C --> H["README.md"]
    D --> I["test_main.py"]

小结:掌握了文件操作命令,你就能像整理房间一样整理你的数字生活!多练习,熟能生巧!


本章小结

本章我们学习了 Linux 文件系统的基础操作!

核心命令回顾:

命令作用常用选项
ls列出目录内容-l 详细信息, -a 显示隐藏, -h 人性化, -R 递归, -S 按大小, -t 按时间
pwd显示当前目录-P 显示物理路径
cd切换目录~ 家目录, - 上次目录, .. 上级目录
mkdir创建目录-p 递归创建, -v 显示过程
touch创建空文件/更新时间-d 设置日期
cp复制文件/目录-r 递归, -i 询问, -v 显示, -p 保留属性
mv移动/重命名-i 询问
rm删除文件/目录-r 递归, -f 强制

重要安全提示:

  • rm 没有"回收站",删了就是删了!
  • 建议把 alias rm='rm -i' 加到 ~/.bashrc
  • 或者使用 trash-cli 工具替代 rm

通配符总结:

  • * = 匹配任意字符
  • ? = 匹配单个字符
  • [] = 匹配范围内字符
  • {} = 生成序列

下一章我们将学习文件查看与编辑器,包括 catlessvim 等查看和编辑文件的神器!敬请期待!

最后修改 March 24, 2026: 新增JavaScript教程 (37305c4)