☰
实战 Bash 脚本:删除目录(含子目录)中所有空文件的完整指南 —— devops-exercises 之 Empty Files 习题解析
2026/10/2 12:41:53 网站建设 项目流程
  • 文档
  • 教程
  • DevOps
  • 运维

【免费下载链接】devops-exercises

Linux, Jenkins, AWS, SRE, Prometheus, Docker, Python, Ansible, Git, Kubernetes, Terraform, OpenStack, SQL, NoSQL, Azure, GCP, DNS, Elastic, Network, Virtualization. DevOps Interview Questions

项目地址:https://gitcode.com/GitHub_Trending/de/devops-exercises
点击查看免费下载

本篇指南围绕开源仓库 devops-exercises 中topics/shell系列练习 "Empty Files"(习题原文、官方参考答案)展开,讲解如何编写一个 Bash 脚本,删除指定目录及其嵌套子目录中的所有空文件。读完本文,你将掌握for循环遍历、-s文件大小测试、find递归搜索以及空文件清理的安全写法,并能把思路复用到磁盘清理、日志归档、构建产物回收等真实运维场景。

一、题目回顾:目标与约束

原练习(topics/shell/empty_files.md)给出的目标非常简洁:

Write a script to remove all the empty files in a given directory (including nested directories)

即:编写一个脚本,删除给定目录中的全部空文件,并且必须包含嵌套子目录。该练习被归类在topics/shell/README.md的 "Shell Scripting Exercises" 表格中,难度标记为Basic,主题为Misc,是整套 shell 练习(Hello World、Basic date、Factors、Argument Check、Files Size、Count Chars、Sum、Number of Arguments、Directories Comparison、Host Status)中的一环,适合在掌握变量、条件判断、for循环之后练习文件系统操作。

二、官方参考答案逐行拆解

仓库给出的解决方案(topics/shell/solutions/empty_files.md)如下:

#! /bin/bash for x in * do if [ -s $x ] then continue else rm -rf $x fi done

逐行解读其原理:

  1. #! /bin/bash:Shebang 行,声明用 Bash 解释器执行。仓库 README 的自测题也强调/bin/bash是 Bourne-again shell,功能完善、语法更佳,可执行绝大多数脚本。
  2. for x in *:让 shell 对当前目录下的每个条目(文件名或目录名)做通配符展开,逐个绑定到变量$x。注意:*默认不包含隐藏文件(以.开头),也不递归进入子目录。
  3. if [ -s $x ]:-s是 Bash 的文件测试运算符,判断文件存在且大小大于 0。条件为真(文件非空)时continue跳过;为假(空文件)则进入else分支。
  4. rm -rf $x:删除该条目。由于空文件大小为零,-s测试为假,因此会被删除。

需要特别指出的局限:

  • 官方版本只能清理当前目录第一层的空文件/空目录,无法满足题目中 "including nested directories"(含嵌套目录)的要求;
  • 它对空目录也会执行rm -rf(-s对空目录同样为假),需要结合需求判断是否符合预期;
  • 未加双引号"$x",当文件名包含空格或通配符字符时会出问题;
  • 未做任何参数校验,也没有提示输出。

三、对照同系列练习,理解脚本设计模式

"Empty Files" 在仓库中属于topics/shell系列的一部分,对比同目录其他题解(solutions 目录)可以总结出几条 Bash 脚本设计的惯用模式:

  • Shebang 风格:files_size.md、count_chars.md等使用#!/usr/bin/env bash(更便于在 PATH 中定位 bash),官方答案用的#! /bin/bash则直接指定绝对路径,两者均可接受。
  • 循环遍历:本题和 Files Size 题解(for i in $(ls -S1); do ... done)都演示了for循环遍历目录条目的写法,是 shell 习题的基础考点。
  • 条件判断:与 Argument Check 题解 使用的[[ ${1} == "pizza" ]]双括号条件、Directories Comparison 题解 使用的if test $# -ne 2类似,本题的[ -s $x ]属于单括号测试表达式,是test命令的简写形式。
  • 退出码用法:Host Status 题解 中ping失败后依据$?判断是否发告警邮件,说明脚本中"检查命令结果再决定分支"是常见模式;本题则通过-s测试的返回真伪决定删除与否。

四、升级方案一:用find递归删除嵌套目录中的空文件

原官方答案没有真正实现"嵌套目录"递归,最直接、最安全的改进是借助find:

#!/usr/bin/env bash # 用法: ./remove_empty.sh <目录> target_dir="${1:-.}" if [ ! -d "$target_dir" ]; then echo "Error: $target_dir is not a directory" >&2 exit 1 fi find "$target_dir" -type f -empty -delete echo "Empty files under $target_dir have been removed."

要点说明:

  • -type f:只匹配普通文件,避免误删目录;-empty匹配大小为 0 的文件;-delete直接删除匹配项。
  • 三者组合即"递归删除给定目录树内所有空文件",完整满足原题 "including nested directories" 的目标。
  • 用-type d -empty可单独清理空目录(如find "$target_dir" -type d -empty -delete,注意应先深后浅以避免目录层级问题)。
  • 如需"预览而不删除",把-delete换成-print即可列出所有将被删除的空文件,这是生产环境最稳妥的演练方式。

五、升级方案二:保留for循环语义的递归版本

若希望保留官方答案的for循环教学思路,同时补齐递归能力,可结合find的输出驱动循环:

#!/usr/bin/env bash target_dir="${1:-.}" while IFS= read -r -d '' file; do if [ ! -s "$file" ]; then echo "Removing empty file: $file" rm -- "$file" fi done < <(find "$target_dir" -type f -print0)

设计要点:

  • -print0与read -d ''配合,以 NUL 分隔文件名,可正确处理含空格、换行或特殊字符的文件名;
  • [ ! -s "$file" ]即"文件不存在或大小为零"(-s取反),与官方答案的if [ -s $x ]逻辑互补但语义更严谨;
  • rm -- "$file"中--防止以-开头的文件名被误认为选项,双引号防止分词与通配符展开;
  • 增加了echo提示,让每次删除可审计、可回查。

六、边界情况与生产环境注意事项

无论采用哪种写法,处理空文件清理时都应考虑以下边界:

  1. 只删除空文件而非空目录:官方答案因-s对空目录同样为假,会把空目录一并rm -rf;若需求仅限文件,务必加-type f或[ -f "$x" ]判断。
  2. 隐藏文件:for x in *不匹配.开头的文件,find默认会遍历隐藏文件——两种行为差异需根据清理目标确认。
  3. 权限问题:无写权限的文件/目录会导致rm或find -delete失败;可先用-print模拟,或对失败退出码做处理。
  4. 符号链接:find -type f默认不跟随符号链接,需明确是否清理链接指向的空目标。
  5. 安全删除:rm -rf是危险命令,本文仅作技术讲解;实际使用建议先-print预览,或把文件移入回收目录而非直接rm。

七、与本仓库其他模块的联系与延伸

topics/shell目录在仓库中对应 README 与 12 道基础练习题,从变量、算术、条件、循环到函数、case 语句循序渐进;"Empty Files" 的 Misc 定位恰好是综合运用for循环与文件测试运算符的典型代表。同时,仓库 scripts 目录中的 count_questions.sh 使用set -eu并借助grep | awk统计练习题数量、回写 README,展示了真实运维脚本对"失败即退出、可重复执行"的追求——与之对比,删除空文件的脚本同样建议加上set -e(按 README 自测题的说明,set -e可在命令失败时立即退出脚本,避免连锁错误)。如果你已掌握本练习,可继续挑战同系列难度为 Intermediate 的 Host Status(探测主机存活)与 Directories Comparison(目录差异比对),进一步巩固 shell 实战能力。

小结:官方答案用 10 行代码演示了 Bash 的for循环与-s测试,但受限于通配符展开不递归的特性,实际生产中推荐find -type f -empty -delete或"find -print0+ 循环"的方案,才能真正覆盖嵌套目录,并在文件名安全、空目录误删、可预览性等方面做到生产可用。

  • 文档
  • 教程
  • DevOps
  • 运维

【免费下载链接】devops-exercises

Linux, Jenkins, AWS, SRE, Prometheus, Docker, Python, Ansible, Git, Kubernetes, Terraform, OpenStack, SQL, NoSQL, Azure, GCP, DNS, Elastic, Network, Virtualization. DevOps Interview Questions

项目地址:https://gitcode.com/GitHub_Trending/de/devops-exercises
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询