【Linux】常用指令详解(一)目录与文件操作
概览
- pwd、ls、cd,以及绝对路径和相对路径
- tree 看目录树
- touch、stat、file 看文件属性
- mkdir、rmdir、rm 建目录和删东西
- cp、mv 复制、移动、改名
命令
pwd (看当前位置)
# 所属目录:/home/cocatrice,下同
pwd # 打印当前工作目录的绝对路径
pwd 是 shell 内建命令,打印的是 PWD 变量,不带任何选项,路径永远是绝对路径。
pwd 是判断路径的起点,后面每条命令能不能找到目标,取决于你此刻站在哪一层。敲命令之前先 pwd,是个能省很多时间的习惯,尤其是刚从别的目录 cd 过来、或者刚 su 到另一个账号的时候。这里有两个细节值得留意:一是 pwd 属于 shell 内建,不走 PATH,也不会因为 /usr/bin 出问题就失效;二是 shell 会维护一条逻辑路径,如果一路都是 cd 进来的,打印出来的就是拼接结果,遇到软链接显示的是链接本身的名字,要看内核视角的真实位置得加 -P。
ls (看目录内容)
# 所属目录:/home/cocatrice
ls # 只列名字
ls -a # 连隐藏文件一起列,含 . 和 ..
ls -l # 长格式,权限、属主、大小、时间
ls -al # 两个选项叠加,长格式加隐藏文件
ls -alF # F 给目录名补一个 /
ls -alFn # n 把属主和属组显示成 uid、gid
ls -1 # 一行只输出一个名字
ls -s # 每个名字前面带上占用的块数
ls -R # 递归列出所有子目录
ls 是敲得最多的命令,也最容易被当成理所当然。它默认只列名字,把以点开头的文件过滤掉,输出还按终端宽度自动分列,所以同一个目录在宽屏和窄屏、在终端里和重定向到文件里,看起来完全不一样。判断输出时先看有没有 -l,没有 -l 就只能拿到名字,权限、大小、时间全都看不到;有了 -l,第一列是类型加权限,第三列是属主,第五列是字节数,后面是时间,末尾才是名字。
Linux 的文件系统是一棵以 / 为根的树,每个文件都有唯一一条从根出发的路径。绝对路径从 / 写起,换到哪都不会变;相对路径从当前工作目录写起,换一个目录再执行同一串字符,指向的就变了。用 . 表示当前目录,.. 表示上一级,路径里这两个符号会被一步步解开。

图 1 目录树、绝对路径与相对路径
cd (切换目录)
cd 改的是当前这个 shell 进程的工作目录,只影响你和你的子进程,别的终端窗口不受影响,这也是两个窗口能各自待在不同目录的原因。路径写法决定了 cd 能不能成功:以斜杠开头的是绝对路径,从根目录一路写到底;其余都是相对路径,从当前目录算起。分不清的时候就先 pwd 再拼,比凭感觉猜快得多。
# 所属目录:/home/cocatrice
cd .. # 上一级,回到 /home
cd /home/cocatrice # 绝对路径
cd dir # 相对路径,进入家目录下的 dir
cd ~ # 家目录,也可以直接写 cd
cd – # 回上一次所在的目录
cd 改的是当前这个 shell 进程的工作目录,只影响本 shell 和它启动的子进程,新开一个终端不继承。cd – 依赖 shell 里的 OLDPWD 变量,记的是上一次所在的目录,和命令历史没有关系。
选项怎么选:cd 后面什么都不跟等于 cd ~,都回家目录;cd – 回上一次待过的目录,来回切很顺手,但它只记一个位置,连敲三次是来回弹而不是一层层回退;cd … 上一层,cd …/… 上两层,层数多了容易数错;那个波浪号是 shell 先展开再交给 cd 的,写在引号里面就不会展开。

图 2 cd … 与 cd – 前后的目录变化
tree (看目录树)
tree 的价值在于把层级关系一次画出来,比连着敲几次 ls 直观得多,也更容易发现层级是不是建歪了。它默认展开全部层级,目录一深输出就很长,所以敲之前先想清楚要看几层。
# 所属目录:/home/cocatrice
tree path1 # 递归显示目录结构,没装先装: sudo yum install -y tree
tree -L 1 path1 # 只展开一层
选项怎么选:只想看第一层,用 -L 1;只看某个子目录,把路径写在后面;只要目录不要文件,加 -d。tree 不是默认安装的,最小化安装的系统上得先装,这一点在写脚本时要注意,脚本里直接调 tree 换台机器就会失败。输出的收尾那行统计也别跳过,目录数和文件数和预期对不上,说明有层级没展开。
touch(看文件属性)
# 所属目录:/home/cocatrice
touch newFile.txt # 文件不存在就建一个空文件
touch -a newFile.txt # 只改访问时间 Access
touch -m newFile.txt # 只改内容修改时间 Modify
stat newFile.txt # 看 inode、权限、三个时间
file newFile.txt # 看文件类型
这一组不改内容,只管文件身上那层元数据。名字、大小、属主、权限、三个时间都记在 inode 里,和文件内容分开存放。理解这一点之后很多现象就顺了:改名字内容没动,改权限内容也没动,重命名在同一分区里几乎是瞬间完成的。
三个时间要分清楚:Access 是最近一次被读的时间,Modify 是内容最近一次被改的时间,Change 是 inode 本身最近一次被改的时间。改权限、改属主、改名字都会刷新 Change,所以只看 Modify 会漏掉很多动作。用 -a 和 -m 可以分别只动前两个,不过两个操作都会顺带把 Change 刷新一次。要快速拿到某几个字段,用 stat -c 加格式串比看整屏输出省事。file 判断类型靠读文件头部的魔数,不看扩展名,所以把后缀从 .txt 改成 .png 骗不过它。
ls -l 的每一列含义固定,从左到右是文件类型加权限、硬链接数、属主、属组、大小、修改时间、文件名。第一列共 10 个字符,第一位是文件类型,d 是目录,- 是普通文件,l 是软链接,b 是块设备,c 是字符设备,p 是管道,s 是套接字;后面 9 位每 3 位一组,依次是属主、属组、其他人的 r、w、x。这一列会读,权限题的输出判读就稳了。
选项怎么选:只想知道文件在不在,用 ls;想连隐藏文件一起看,加 -a,多出来的 . 和 … 是每个目录都自带的;想看权限和属主,加 -l;想一眼分出文件和目录,加 -F,目录名后面会多一个斜杠;属主显示成数字更利于排查权限问题,加 -n 把 uid 打出来;递归的 -R 在大目录上输出会非常长,除非确定目录很小,否则别随手加。

图 3 ls -l 输出每一列的含义
mkdir,rmdir,rm (建目录、删目录、删文件)
建和删是破坏性最强的一组,敲之前脑子里要有目录树的形状。三个命令分工很明确:mkdir 只建目录,rmdir 只删空目录,rm 删文件和目录树。这样设计是有意的,删空目录最安全,一旦里面有东西就停下来报错,等于给你留了一次反悔的机会。
# 所属目录:/home/cocatrice
mkdir mydir # 建一层目录
mkdir -p path1/path2/path3/path4 # 一次建多层,缺哪层补哪层
rmdir mydir # 只能删空目录
rmdir -p path1/path2/path3/path4 # 自底向上逐级删空目录
rm file.txt # 删文件
rm -r dir # 递归删目录
rm -i newFile.txt # 删前逐个确认
rm -ri d # 递归删并且每一层都问
rm 删的是目录里的一条目录项,文件的数据块和 inode 要等引用计数减到 0 才真正释放。能不能删掉一个文件,看的是父目录有没有写权限和执行权限,不看文件自己的权限。这点在权限那一篇还会用到。
选项怎么选:建多层必须用 -p,不然中间缺层会报 No such file or directory;删多层空目录用 rmdir -p,它从最里层往外删,删到某一层非空就停住,前面已经删掉的那些不会恢复;删文件用 rm,加 -i 每个都问一遍;删目录树用 rm -r,确认路径没写错之后再加 -f 跳过确认。rm -rf 没有回收站,执行前把路径从头到尾读一遍是唯一可靠的保护。
cp,mv (复制、移动、改名)
复制和移动的差别不只是位置变没变,底层行为也不一样。cp 一定产生新数据,新文件的 inode 和源文件没有关系,改哪一份都不影响另一份;mv 在同一个文件系统里只挪目录项,数据块和 inode 都不动,所以快,权限和时间这些元数据也一起带过去。跨文件系统的时候 mv 会退化成先复制再删源。
# 所属目录:/home/cocatrice
cp myfile.txt myfile-backup.txt # 复制出一个新文件
cp *.txt dir # 通配符匹配多个文件,一起复制进目录
cp -i myfile.txt myfile-backup.txt # 覆盖前先问
cp -r dir dir2 # 递归复制整个目录
mv myfile.txt yourfile.txt # 改名
mv -i yourfile.txt myfile.txt # 目标存在时问一下再覆盖
mv myfile.txt dir # 移动进目录
mv temp2 tmp3 # 目录改名
cp 复制出来的是新文件、新 inode,和源文件互不影响;mv 在同一个文件系统里只改目录项,不搬数据,所以快,inode 也保留。目标位置有同名文件时,两者默认都直接覆盖。
选项怎么选:目标目录里已经有同名文件时,cp 和 mv 默认直接覆盖且不留痕迹,想稳妥就加 -i 逐个确认;复制目录必须加 -r,漏了这个选项遇到目录会跳过并给一句提示;一次复制多个文件时,末尾那个参数必须是已经存在的目录,否则会被当成目标文件名。通配符是 shell 先展开再交给命令的,匹配不到任何文件时 bash 会把星号原样传下去,命令只能报 cannot stat。
选项速查
| pwd | -P | 要看软链接背后的真实路径 |
| ls | -a / -l / -F / -n | 看隐藏文件 / 看权限属主 / 分辨文件和目录 / 显示数字属主 |
| cd | – | 回到上一次待过的目录 |
| tree | -L n / -d | 限制展开层数 / 只看目录 |
| touch | -a / -m | 只改访问时间 / 只改内容时间 |
| stat | -c | 只要指定字段,不打印整屏 |
| mkdir | -p | 一次建多层目录 |
| rmdir | -p | 逐级删空目录 |
| rm | -r / -i / -f | 删目录 / 逐个确认 / 强制不询问 |
| cp | -r / -i | 复制目录 / 覆盖前询问 |
| mv | -i | 覆盖前询问 |
测试代码及用例
正常情况
[cocatrice@hcss-ecs-4cd1 ~]$ pwd
/home/cocatrice
[cocatrice@hcss-ecs-4cd1 ~]$ ls
dir file.txt temp2
[cocatrice@hcss-ecs-4cd1 ~]$ ls -a
. .. dir file.txt temp2
[cocatrice@hcss-ecs-4cd1 ~]$ ls -l
total 8
drwxrwxr-x 2 cocatrice cocatrice 4096 Sep 17 21:43 dir
-rw-rw-r– 1 cocatrice cocatrice 0 Sep 17 21:43 file.txt
drwxrwxr-x 2 cocatrice cocatrice 4096 Sep 17 21:43 temp2
[cocatrice@hcss-ecs-4cd1 ~]$ ls -al
total 16
drwxrwxr-x 4 cocatrice cocatrice 4096 Sep 17 21:43 .
drwx—— 9 cocatrice cocatrice 4096 Sep 17 21:43 ..
drwxrwxr-x 2 cocatrice cocatrice 4096 Sep 17 21:43 dir
-rw-rw-r– 1 cocatrice cocatrice 0 Sep 17 21:43 file.txt
drwxrwxr-x 2 cocatrice cocatrice 4096 Sep 17 21:43 temp2
[cocatrice@hcss-ecs-4cd1 ~]$ ls -alF
total 16
drwxrwxr-x 4 cocatrice cocatrice 4096 Sep 17 21:43 ./
drwx—— 9 cocatrice cocatrice 4096 Sep 17 21:43 ../
drwxrwxr-x 2 cocatrice cocatrice 4096 Sep 17 21:43 dir/
-rw-rw-r– 1 cocatrice cocatrice 0 Sep 17 21:43 file.txt
drwxrwxr-x 2 cocatrice cocatrice 4096 Sep 17 21:43 temp2/
[cocatrice@hcss-ecs-4cd1 ~]$ ls -alFn
total 16
drwxrwxr-x 4 1000 1000 4096 Sep 17 21:43 ./
drwx—— 9 1000 1000 4096 Sep 17 21:43 ../
drwxrwxr-x 2 1000 1000 4096 Sep 17 21:43 dir/
-rw-rw-r– 1 1000 1000 0 Sep 17 21:43 file.txt
drwxrwxr-x 2 1000 1000 4096 Sep 17 21:43 temp2/
[cocatrice@hcss-ecs-4cd1 ~]$ ls -1
dir
file.txt
temp2
[cocatrice@hcss-ecs-4cd1 ~]$ ls -s
total 8
4 dir 0 file.txt 4 temp2
[cocatrice@hcss-ecs-4cd1 ~]$ ls -R
.:
dir file.txt temp2
./dir:
./temp2:
这几段输出放在一起对比就能看出选项的作用:不带选项只有名字,加了 -a 多出两个点开头的条目,加了 -l 才出现权限、属主、大小和时间,再加 -F 目录名后面多一个斜杠,换成 -n 属主就变成数字。第一列的第一位是类型,后面九位才是权限,这个顺序在所有 Linux 上都一样。
[cocatrice@hcss-ecs-4cd1 ~]$ pwd
/home/cocatrice
[cocatrice@hcss-ecs-4cd1 ~]$ cd ..
[cocatrice@hcss-ecs-4cd1 ~]$ pwd
/home
[cocatrice@hcss-ecs-4cd1 ~]$ cd /home/cocatrice
[cocatrice@hcss-ecs-4cd1 ~]$ pwd
/home/cocatrice
[cocatrice@hcss-ecs-4cd1 ~]$ cd dir
[cocatrice@hcss-ecs-4cd1 ~]$ pwd
/home/cocatrice/dir
[cocatrice@hcss-ecs-4cd1 ~]$ cd ~
[cocatrice@hcss-ecs-4cd1 ~]$ pwd
/home/cocatrice
[cocatrice@hcss-ecs-4cd1 ~]$ cd /
[cocatrice@hcss-ecs-4cd1 ~]$ pwd
/
[cocatrice@hcss-ecs-4cd1 ~]$ cd –
[cocatrice@hcss-ecs-4cd1 ~]$ pwd
/home/cocatrice
这一段把四种路径写法都跑了一遍,每个 pwd 的结果就是答案:cd … 从家目录退到 /home,绝对路径一步到位,相对路径跟着当前目录走,cd – 在根目录和家目录之间来回弹。
[cocatrice@hcss-ecs-4cd1 ~]$ mkdir -p path1/path2/path3/path4
[cocatrice@hcss-ecs-4cd1 ~]$ tree path1
path1
└── path2
└── path3
└── path4
3 directories, 0 files
[cocatrice@hcss-ecs-4cd1 ~]$ tree -L 1 path1
path1
└── path2
1 directory, 0 files
两段 tree 的输出差一层,说明 -L 1 只展开了第一层,收尾的统计也跟着从 3 directories 变成 1 directory。
[cocatrice@hcss-ecs-4cd1 ~]$ touch newFile.txt
[cocatrice@hcss-ecs-4cd1 ~]$ stat newFile.txt
File: ‘newFile.txt’
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: fd01h/64769d Inode: 666395 Links: 1
Access: (0664/-rw-rw-r–) Uid: ( 1000/cocatrice) Gid: ( 1000/cocatrice)
Access: 2026-09-17 21:43:42.466588128 +0800
Modify: 2026-09-17 21:43:42.466588128 +0800
Change: 2026-09-17 21:43:42.466588128 +0800
Birth: –
[cocatrice@hcss-ecs-4cd1 ~]$ file newFile.txt
newFile.txt: empty
[cocatrice@hcss-ecs-4cd1 ~]$ file dir
dir: directory
touch -a 只动 Access,touch -m 只动 Modify,两个都会顺带把 Change 刷新,因为 inode 本身变了。
前后两段 stat 连起来看更清楚:第一段里 Access 变了而 Modify 没动,说明 -a 只碰了访问时间;第二段里 Modify 变了而 Access 没动,说明 -m 只碰了内容时间;Change 两段都在变,因为它记的是 inode 被改动的时刻,而不是文件内容。
[cocatrice@hcss-ecs-4cd1 ~]$ touch -a newFile.txt
[cocatrice@hcss-ecs-4cd1 ~]$ stat -c 'Access=%x%nModify=%y%nChange=%z' newFile.txt
Access=2026-09-17 21:43:42.468588131 +0800
Modify=2026-09-17 21:43:42.466588128 +0800
Change=2026-09-17 21:43:42.468588131 +0800
[cocatrice@hcss-ecs-4cd1 ~]$ touch -m newFile.txt
[cocatrice@hcss-ecs-4cd1 ~]$ stat -c 'Access=%x%nModify=%y%nChange=%z' newFile.txt
Access=2026-09-17 21:43:42.468588131 +0800
Modify=2026-09-17 21:43:42.469588132 +0800
Change=2026-09-17 21:43:42.469588132 +0800
[cocatrice@hcss-ecs-4cd1 ~]$ mkdir mydir
[cocatrice@hcss-ecs-4cd1 ~]$ ls -l
total 12
drwxrwxr-x 2 cocatrice cocatrice 4096 Sep 17 21:43 dir
-rw-rw-r– 1 cocatrice cocatrice 0 Sep 17 21:43 file.txt
drwxrwxr-x 2 cocatrice cocatrice 4096 Sep 17 21:43 mydir
-rw-rw-r– 1 cocatrice cocatrice 0 Sep 17 21:43 newFile.txt
drwxrwxr-x 2 cocatrice cocatrice 4096 Sep 17 21:43 temp2
[cocatrice@hcss-ecs-4cd1 ~]$ rmdir mydir
[cocatrice@hcss-ecs-4cd1 ~]$ ls -l
total 8
drwxrwxr-x 2 cocatrice cocatrice 4096 Sep 17 21:43 dir
-rw-rw-r– 1 cocatrice cocatrice 0 Sep 17 21:43 file.txt
-rw-rw-r– 1 cocatrice cocatrice 0 Sep 17 21:43 newFile.txt
drwxrwxr-x 2 cocatrice cocatrice 4096 Sep 17 21:43 temp2
两段 ls -l 之间只少了 mydir 一行,说明 rmdir 只删掉一个空目录,其他文件一个都没动,这正是它和 rm -r 的区别。
[cocatrice@hcss-ecs-4cd1 ~]$ echo "hello bite" > myfile.txt
[cocatrice@hcss-ecs-4cd1 ~]$ cp myfile.txt myfile-backup.txt
[cocatrice@hcss-ecs-4cd1 ~]$ ls -l myfile.txt myfile-backup.txt
-rw-rw-r– 1 cocatrice cocatrice 11 Sep 17 21:43 myfile-backup.txt
-rw-rw-r– 1 cocatrice cocatrice 11 Sep 17 21:43 myfile.txt
[cocatrice@hcss-ecs-4cd1 ~]$ cp *.txt dir
[cocatrice@hcss-ecs-4cd1 ~]$ tree dir
dir
├── file.txt
├── myfile-backup.txt
├── myfile.txt
└── newFile.txt
0 directories, 4 files
[cocatrice@hcss-ecs-4cd1 ~]$ cp -i myfile.txt myfile-backup.txt
cp: overwrite ‘myfile-backup.txt’? y
[cocatrice@hcss-ecs-4cd1 ~]$ cp -r dir dir2
[cocatrice@hcss-ecs-4cd1 ~]$ tree dir2
dir2
├── file.txt
├── myfile-backup.txt
├── myfile.txt
└── newFile.txt
0 directories, 4 files
这一段里 cp -r 把整个 dir 复制成 dir2,两棵 tree 的输出完全一样,说明目录结构和里面的文件都被带过去了。
[cocatrice@hcss-ecs-4cd1 ~]$ echo "hello bite tech" > myfile.txt
[cocatrice@hcss-ecs-4cd1 ~]$ cp myfile.txt myfile-backup.txt
[cocatrice@hcss-ecs-4cd1 ~]$ cat myfile-backup.txt
hello bite tech
[cocatrice@hcss-ecs-4cd1 ~]$ mv myfile.txt yourfile.txt
[cocatrice@hcss-ecs-4cd1 ~]$ ls myfile.txt
ls: cannot access myfile.txt: No such file or directory
[cocatrice@hcss-ecs-4cd1 ~]$ touch myfile.txt
[cocatrice@hcss-ecs-4cd1 ~]$ mv -i yourfile.txt myfile.txt
mv: overwrite ‘myfile.txt’? y
[cocatrice@hcss-ecs-4cd1 ~]$ ls -l myfile.txt
-rw-rw-r– 1 cocatrice cocatrice 16 Sep 17 21:43 myfile.txt
几段连起来看能把 cp 和 mv 分清:cp 之后两个文件同时存在,mv 改名之后旧名字立刻查不到,mv -i 覆盖前多问了一句,返回码和文件内容都对得上。
常见报错
| mkdir: cannot create directory ‘path1/path2/path3’: No such file or directory | mkdir 不带 -p | 中间层级不存在,mkdir 一次只建一层 |
| rm: cannot remove ‘dir9’: Is a directory | rm 不带 -r | 删目录必须递归,rm 默认只删文件 |
| rmdir: failed to remove directory ‘path1/path2’: Directory not empty | rmdir 删非空目录 | 目录里还有条目,rmdir 只处理空目录 |
| ls: cannot access myfile.txt: No such file or directory | 改名之后按旧名字查 | 文件已经改名,旧名字不再存在 |
改前
# 所属目录:/home/cocatrice
mkdir path1/path2/path3 # 中间层级不存在,直接失败
[cocatrice@hcss-ecs-4cd1 ~]$ mkdir path1/path2/path3
mkdir: cannot create directory ‘path1/path2/path3’: No such file or directory
改后
# 所属目录:/home/cocatrice
mkdir -p path1/path2/path3 # 加 -p,缺的层级自动补齐
[cocatrice@hcss-ecs-4cd1 ~]$ mkdir -p path1/path2/path3
[cocatrice@hcss-ecs-4cd1 ~]$ tree path1
path1
└── path2
└── path3
2 directories, 0 files
改前
# 所属目录:/home/cocatrice
rm dir9 # 不带 -r,删目录失败
[cocatrice@hcss-ecs-4cd1 ~]$ mkdir dir9
[cocatrice@hcss-ecs-4cd1 ~]$ rm dir9
rm: cannot remove ‘dir9’: Is a directory
改后
# 所属目录:/home/cocatrice
rm -r dir9 # 加 -r 递归删除
[cocatrice@hcss-ecs-4cd1 ~]$ rm -r dir9
[cocatrice@hcss-ecs-4cd1 ~]$ ls
dir dir2 file.txt myfile-backup.txt newFile.txt tmp3
改前
# 所属目录:/home/cocatrice
touch path1/path2/myfile.txt # 里面放一个文件,让它非空
rmdir -p path1/path2/path3/path4 # 非空就删不动
[cocatrice@hcss-ecs-4cd1 ~]$ mkdir -p path1/path2/path3/path4
[cocatrice@hcss-ecs-4cd1 ~]$ touch path1/path2/myfile.txt
[cocatrice@hcss-ecs-4cd1 ~]$ tree path1
path1
└── path2
├── myfile.txt
└── path3
└── path4
3 directories, 1 file
[cocatrice@hcss-ecs-4cd1 ~]$ rmdir -p path1/path2/path3/path4
rmdir: failed to remove directory ‘path1/path2’: Directory not empty
改后
# 所属目录:/home/cocatrice
rm -rf path1 # 递归强制删,整棵树一起走
[cocatrice@hcss-ecs-4cd1 ~]$ rm -rf path1
[cocatrice@hcss-ecs-4cd1 ~]$ ls
dir dir2 file.txt myfile-backup.txt newFile.txt tmp3
rm -rf 会直接删掉整棵目录树,不进回收站,也没有二次确认。执行前把路径从头到尾读一遍,确认没写错再敲,尤其不要写成 rm -rf /* 或者带空格的通配符。
边界情况
[cocatrice@hcss-ecs-4cd1 ~]$ find path1
path1
path1/path2
path1/path2/myfile.txt
[cocatrice@hcss-ecs-4cd1 ~]$ rm -i newFile.txt
rm: remove regular empty file ‘newFile.txt’? y
[cocatrice@hcss-ecs-4cd1 ~]$ stat -c '%y' newFile.txt
2026-09-17 21:43:42.469588132 +0800
[cocatrice@hcss-ecs-4cd1 ~]$ sleep 1
[cocatrice@hcss-ecs-4cd1 ~]$ touch newFile.txt
[cocatrice@hcss-ecs-4cd1 ~]$ stat -c '%y' newFile.txt
2026-09-17 21:43:43.503589416 +0800
[cocatrice@hcss-ecs-4cd1 ~]$ mkdir -p temp && touch temp/a.txt
[cocatrice@hcss-ecs-4cd1 ~]$ mv temp ../
mv: cannot move ‘temp’ to ‘../temp’: Permission denied
踩坑点
- rm 不带 -r 删目录一定失败,要删目录树用 rm -r,确认无误再加 -f,rm -rf 没有回收。
- mkdir 建多层必须带 -p,否则中间缺层直接报 No such file or directory。
- cp 复制目录必须带 -r,目标目录里已有同名文件会静默覆盖,加 -i 逐个问。
- 绝对路径和相对路径的锚点不一样。绝对路径从 / 开始,唯一,不随工作目录变化;相对路径从当前工作目录开始,换目录就指向别处。配置文件里写绝对路径,命令行里用相对路径。
- 目录的 rwx 和文件的 rwx 是两套含义。目录的 x 是能不能进去和能不能穿过它访问下层,目录的 r 是能不能列出里面的名字,目录的 w 是能不能在里面新建或删除条目。文件的 x 才是能不能执行。删除文件看父目录,不看文件自己,这一点最容易混。
- . 和 .. 是每个目录里都有的两个目录项,. 指自己,.. 指上级,普通 ls 默认过滤掉,ls -a 才显示。硬链接数因此至少是 2。
- ls -l 第一列第一位是类型,不是权限。权限只有后面 9 位,顺序固定是拥有者、所属组、other,每组 r、w、x,缺位用 – 占位。把 d 当成权限位来数是常见的错。
- 通配符 * 是 shell 先展开再交给命令的,不是 cp 或 ls 自己认的。匹配不到任何文件时,不同 shell 处理不同,bash 默认把 * 原样传下去,于是会出现 cannot stat 的报错。
- cd – 只记上一次,连续敲是来回切,不是回退历史里的每一层。想按层回退要自己数 cd ..。
本篇总结(模拟面试问题)
问:绝对路径和相对路径的区别,各自用在什么场合?
核心要点:绝对路径从根目录 / 开始,唯一,不随工作目录变化,服务配置里常用。相对路径从当前目录开始,写起来短,命令行里常用,换目录就失效。
问:rm 和 rmdir 的区别?
核心要点:rm 删文件,加 -r 才能删目录,加 -f 强制不询问。rmdir 只删空目录,加 -p 可以逐级删空目录,遇到非空就报 Directory not empty。
问:cp 和 mv 在目标同名时怎么处理?
核心要点:默认都直接覆盖,加 -i 覆盖前询问,加 -f 强制不询问。mv 在同目录内就是改名,跨目录就是移动,同一文件系统内不复制数据。
问:删掉一个文件,操作系统层面到底删了什么?
核心要点:rm 删的是父目录里那条目录项,inode 链接计数减 1,减到 0 且没有进程打开,数据块才回收。文件还在被打开时,目录项没了但数据还在,进程仍能读写。
问:能不能删一个文件取决于什么权限?
核心要点:取决于父目录有没有 w 和 x。目录的 w 允许增删目录项,x 允许穿过目录访问。跟文件自己的权限没关系,所以 /home 开放写权限时别人能删你的文件,粘滞位就是用来堵这个口子的。
问:mkdir -p a/b/c 底层发生了什么,为什么末级已存在也不报错?
核心要点:一次 mkdir 系统调用只能建一层,-p 是程序按路径逐级调用,遇到 EEXIST 就跳过继续下一层。末级已存在也算已满足,所以静默成功,不带 -p 时报 No such file or directory。
问:cp 和 mv 在跨文件系统时行为差别在哪?
核心要点:mv 同文件系统内只改目录项,不搬数据,速度快,inode 不变;跨文件系统要复制数据再删源,等价于 cp 加 rm。cp 不管同不同文件系统都产生新 inode 和新数据。
问:ls -al 输出的第一行 total 后面的数字表示什么?
核心要点:这批目录项占用的块数,按 1KB 一块统计,不是文件总字节数,也不含隐藏项之外的内容。
问:rm -i 和 -f 一起给出会怎样?
核心要点:后出现的选项覆盖前面的,-f 会压掉 -i 的询问。实际使用不要两个一起给。
问:mkdir -p a/b/c 而 a 已经存在,会报错吗?
核心要点:不会,-p 遇到已存在的层级直接跳过,只建缺的,末级已存在也静默返回。
问:cd .. 之后 pwd 打印什么?
核心要点:打印上一级目录的绝对路径。shell 维护逻辑路径,pwd 默认按 PWD 变量输出,加 -P 才做物理路径解析。
问:drwxrwxr-x 拆开每一位的含义?
核心要点:d 表示目录,接着三组 rwx 依次是拥有者、所属组、other的权限,每组顺序固定读、写、执行,缺位用 -,分别对应八进制 4、2、1,合起来是 775。
问:为什么 ls -a 会多出 . 和 ..?
核心要点:几乎所有目录都含这两个目录项,分别指向自己和父目录,给相对路径和路径解析一个稳定入口。普通 ls 按约定把以 . 开头的名字过滤掉。
问:rmdir -p path1/path2 中途报 Directory not empty,已经删掉的那几层还在吗?
核心要点:不在。rmdir -p 自底向上逐层删,报错前成功的层级已经删掉且不恢复,报错点以及它上面的层级保留。
问:同一个文件系统里 mv 一个 5GB 的文件,为什么几乎是瞬间完成?
核心要点:mv 只改父目录里的目录项,把名字从一个目录挪到另一个目录,数据块和 inode 都不动,所以耗时和数据量无关。
参考
- GNU coreutils 手册,ls、cp、mv、rm、mkdir 的完整选项说明:https://www.gnu.org/software/coreutils/manual/coreutils.html
- ls 手册页:https://man7.org/linux/man-pages/man1/ls.1.html
- rm 手册页:https://man7.org/linux/man-pages/man1/rm.1.html
- 路径解析规则:https://man7.org/linux/man-pages/man7/path_resolution.7.html





