2.1 文件与目录操作命令


2.1 文件与目录操作命令

本节摘要:文件与目录操作是命令行的基本功,也是误操作事故的最高发区。本节从一起空变量引发的递归删除事故复盘讲起,系统覆盖查看、创建、复制、移动、删除五类命令的安全用法,核心是建立"破坏半径"意识:每条命令动手前,先知道它能伤到多远。

事故现场:一个空变量 删掉半棵目录树

周五傍晚,某团队的数据处理脚本报错退出。写脚本的同学登录服务器手工排查,脚本里有一行清理逻辑,大意是根据变量里的路径删除临时目录。他在命令行里手工复现这个逻辑,敲下了类似这样的命令:

rm -rf $WORK_DIR/scratch/

问题在于那一次会话里变量没有设置成功——回顾 1.3 节,Bash 引用未定义变量会展开成空字符串。于是这行命令在展开后变成了:

rm -rf /scratch/

斜杠开头,从根下挂载的 scratch 数据目录开始整棵删除。等他反应过来按 Ctrl 加 C,几百吉字节的数据已经消失了一部分,其中包括尚未同步到备份系统的三小时增量数据。恢复团队忙了一个周末,最终从备份加日志回放找回了绝大部分,但业务停摆的代价已经付出去。

复盘时没人指责那个同学手快——在紧急排障的压力下,人的注意力在问题上而不在命令上,这是常态。真正缺的是两道防线:脚本里没有开启未定义变量报错;手工执行危险命令前没有先"预演"。这两道防线怎么建,就是本节的主线。

一、先看清地形:列目录与切换

一切操作从看清现状开始。列目录用 ls,但默认输出信息量太少,运维日常应该用长格式加人类可读的大小:

ls -lh /var/log
total 486M -rw-r----- 1 syslog adm 95M Aug 16 09:35 syslog -rw-r----- 1 syslog adm 120M Aug 9 09:35 syslog.1 -rw-r--r-- 1 root root 1.1K Aug 16 03:17 alternatives.log drwxr-xr-x 2 root root 4.0K Aug 14 06:25 apt

第一列的权限串、属主属组、大小、时间,每一列都有用——权限和属主是第 4 章的主战场,大小和时间是空间排查的线索。开头那行 total 是目录内文件占用块统计,粗看空间够不够就靠它。

ls 还有几个高频选项值得记住:a 显示隐藏文件(点开头的一切配置文件都藏在这);t 按修改时间排序,配合 t 与 r 倒序,"最近改过什么"一屏看清;目录后跟斜杠标记,一眼区分文件和目录。

切换目录用 cd。相对路径与绝对路径的概念这里不再展开,但两个符号要形成肌肉记忆:单个点表示当前目录,两个点表示上级。运维排错时经常要"到日志的上级看看还有什么",两个点就是日常。

看清当前在哪,永远先看提示符里的路径段——1.3 节讲过它是状态仪表盘的一部分。迷失时一条 pwd 立刻校准。

二、创建与复制:动作小 但有细节

建目录用 mkdir,加 p 选项可以一次建出整条路径,父目录不存在就顺带创建:

mkdir -p /data/app/{logs,tmp,backup}

花括号展开是 Bash 的便利语法,一条命令建出三个子目录。部署应用前的目录准备、按日期建日志归档目录,都是它的舞台。

复制用 cp。最需要记住的细节是:复制目录必须加 r 选项,否则报错;加 a 选项会连权限、属主、时间戳一起复制,做配置备份时用 a 而不是 r——权限信息丢了,恢复回去的服务可能起不来。给配置文件做变更前备份,标准动作是:

sudo cp -a /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak.$(date +%F)

文件名里带上日期,多少次回滚都乱不了。这个小习惯的价值在半年后你想"改之前到底长什么样"时兑现。

移动与改名是同一个命令 mv。它有两个特性要留心:跨文件系统移动实际是复制加删除,大文件移动中断会留半份;mv 覆盖同名文件不提示、不进回收站,瞬间完成。把 mv 当成"可能无声覆盖"的命令对待,覆盖前先 ls 确认目标不存在。

三、删除:把不可逆当默认假设

rm 是命令行里破坏力与便捷性最不成比例的命令。先立规矩,再讲用法。

规矩一,变量参与的路径必须先验证非空:

echo "将删除:$WORK_DIR/scratch/" rm -rf "${WORK_DIR:?}/scratch/"

花括号加冒号问号的写法是 Bash 内建的保险丝:变量为空或未定义时,Shell 直接报错拒绝执行整条命令,而不是展开成空字符串继续跑。开篇那个事故,有这一手就能拦住。

规矩二,通配符先预演。删除前把 rm 换成 ls 跑一遍,亲眼看展开结果:

ls -d /data/tmp/*.log rm /data/tmp/*.log

两行之间的差异只是命令名,但第一行是无代价的预演。通配符展开发生在命令执行前,你以为会匹配三个文件,实际可能匹配三十个——ls 会替你发现这件事。

规矩三,交互确认选项 i 在学习期全程使用,熟练后再有意识地放弃它换取速度。rm 加 i 会在每个目标前询问,删除五个文件要按五次确认,烦,但烦得有价值。

图 2-1 高危命令执行前的三道防线

图 2-1 高危命令执行前的三道防线

四、链接与元信息:两个进阶利器

软链接相当于快捷方式,运维用它做版本切换与路径统一:

ln -s /data/releases/app-20260816 /data/app/current ls -l /data/app/
lrwxrwxrwx 1 root root 33 Aug 16 22:00 current -> /data/releases/app-20260816

发布新版本时把链接指向新目录,回滚时指回旧目录,秒级完成且不留残骸。这个模式在滚动发布里几乎是行业标准。

查看文件类型与元信息用 file 与 stat。file 能识别文件的真实格式——扩展名会骗人,文件头不会。stat 给出比 ls 更全的时间信息,重点看三个时间:访问时间、修改时间、状态变更时间。排错时"这个文件最后一次被改是什么时候"经常是破案的关键一环,stat 直接回答。

五、一次完整的目录操作演练

把本节命令串成一个真实任务:部署前的目录准备。要求:在数据盘建应用目录树,把配置模板复制进去,替换占位符,最后核对。

sudo mkdir -p /data/myapp/{conf,logs,data} sudo cp -a /opt/templates/myapp.conf.sample /data/myapp/conf/myapp.conf sudo sed -i 's/__LISTEN_PORT__/8088/' /data/myapp/conf/myapp.conf ls -lR /data/myapp | head -12
/data/myapp: total 12 drwxr-xr-x 2 root root 4096 Aug 16 22:12 conf drwxr-xr-x 2 root root 4096 Aug 16 22:12 data drwxr-xr-x 2 root root 4096 Aug 16 22:12 logs /data/myapp/conf: total 4 -rw-r--r-- 1 root root 318 Aug 16 22:12 myapp.conf

五行命令完成建树、拷模板、改端口、核对四个动作,全程没有图形界面,全程可以写进部署文档原样重放。这就是命令行的复利:动作即文档。

💡 关键直觉:判断一个人命令行熟不熟,不是看他敲得多快,而是看他删东西之前做了什么。快可以练,稳是习惯。

延伸:把安全习惯变成团队规范

个人习惯靠自觉,团队安全靠规范。围绕文件操作,值得写进团队手册的条款其实很少,但每条都对应着一类真实事故。第一,删除类命令必须预演:通配符删除前先执行对应的列目录版本,这条对资深和新人是同等级别的约束——统计上,误删事故的肇事者工龄分布相当均匀,资历不提供豁免。第二,变量参与的路径必须使用保险丝写法或前置非空校验,脚本合并请求里看到裸变量拼路径就应该打回。第三,配置变更前备份带日期,回滚路径永远存在。第四,跨机器移动数据一律走打包传输,禁止图形工具拖拽——本节开篇第二个事故里权限丢失的教训值得年年讲。

这些条款看起来繁琐,执行成本加起来每单次操作不到十秒。而它们防住的事故,随便一起的代价都是小时级起步。安全习惯的账要这么算:不是拿十秒换一个可能永远不发生的事故,而是拿十秒换"事故发生时你不必向任何人解释为什么没有防线"。后者的价值与事故是否发生无关,它是一种工程上的问心无愧。

常见疑问解答

删掉的文件能找回来吗

传统观念说 Linux 的 rm 不进回收站、无法恢复,严格讲不完全对——文件被删后数据块只是标记为可复用,立即只读挂载原分区、用数据恢复工具扫描,仍有机会找回部分内容。但成功率随时间与写入活动骤降,而且恢复操作本身要求卸载分区、停业务。工程上的正确姿势不是寄望于恢复,而是把力气花在事前:重要数据必须有异地备份,破坏性命令必须走预演。把恢复当最后手段,别当常规能力。

目录删不掉 报"设备或资源忙"怎么回事

这不是权限问题,是目录正被进程占用——通常是某个进程的工作目录停在里面,或文件被打开着。排查顺序:先用 2.3 节的思路确认有无进程持有该目录下的文件,再检查是否有会话停在该目录里。处理完占用者,删除自然成功。这个报错其实是系统在拦你:占着目录的进程可能正在写数据,强删可能造成数据不一致。

cp 覆盖时不提示了 是坏掉了吗

没坏,是别名或选项差异。多数发行版给 root 用户的 cp 配了交互别名,普通用户没有;脚本里交互提示更是灾难——脚本跑到半夜等一个没人回答的确认。所以规范写法是脚本里显式加 yes 选项强制覆盖,交互终端里保留提示。理解"别名只是你终端里的局部习惯",写脚本时永远用命令的本义,能避开一整类"在我机器上是好的"问题。

软链接和硬链接怎么选

日常运维九成场景用软链接:能跨文件系统、能链目录、目标直观可见。硬链接的价值在"同一份数据多个名字且不因一处删除而消失"——备份与去重场景偶有妙用。判断口诀:想当快捷方式用软链,想做数据的多重保险用硬链。顺带一个冷知识:硬链接数体现在 ls 长格式的第二列,看到某文件链接数大于一,说明它还有别的名字散落在别处。

文件名里有空格或特殊符号 处理总出错

核心原则是引号包裹加 Tab 补全。写脚本处理路径时,双引号包变量是默认姿势,空格、括号、中文都伤不了你。另外少用空格命名文件、用下划线或连字符替代,从源头减少麻烦——命名规范是运维的基本修养,好名字不需要转义。

最后交代一个态度问题:本节反复强调删除的谨慎,不是提倡畏手畏脚。恰恰相反,防线建好后你应该更敢动手——正因为知道变量有保险丝、通配符有预演,你才敢在复杂目录里执行批量操作。谨慎与果断不矛盾,防线的意义就是把赌它没事变成确认过没事。没有防线的勇敢叫鲁莽,有防线的谨慎才支撑得起果断。

本节要点回顾

  • 未定义变量展开为空是删除事故第一根源:花括号加冒号问号的保险丝写法要成为肌肉记忆
  • 通配符先 ls 预演再执行:展开发生在执行前,预演零成本
  • 备份用 cp 加 a:保住权限与属主,回滚时配置才原样复活
  • mv 覆盖不提示:目标存在性先确认,跨盘大文件移动注意中断残留
  • 软链接做版本切换:发布与回滚共用一个模式,秒级生效
  • stat 的三个时间是排错线索:谁在什么时候动了文件,它会作证

下一节进入文本的世界——日志是运维的眼睛,而这双眼睛需要正确的打开方式。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U