AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / computer / 问题 / 1863934
Accepted
dargaud
dargaud
Asked: 2024-12-07 02:12:43 +0800 CST2024-12-07 02:12:43 +0800 CST 2024-12-07 02:12:43 +0800 CST

删除仅包含 .directory 文件的目录

  • 772

我已经通过删除目录树中的文件进行了大量清理。我现在想删除空目录,因为现在有很多“几乎为空”的目录:它们仅包含一个隐藏.directory文件。这样做的find -empty结果是……空的。我不想删除包含其他文件的目录的点文件。

我可以想到一些复杂的 bash 脚本find,但我想不出一个简单的方法来实现它...例如这里的解决方案(Linux:删除只有一个文件而没有子目录的所有目录)找不到点文件。

澄清:A.directory是 KDE(?)创建的隐藏文本文件dolphin,包含有关如何显示目录内容的信息,例如缩略图、文件列表或仅仅是它们的图标等……当文件被删除时,该.directory文件会保留下来,但现在基本上没用了。

linux
  • 3 3 个回答
  • 284 Views

3 个回答

  • Voted
  1. Kamil Maciorowski
    2024-12-07T08:11:37+08:002024-12-07T08:11:37+08:00

    你提到了find -empty,所以你的find可能是 GNU find。在这个答案中,我将使用 GNU 的几个不可移植功能find。

    请先在可扩展目录中测试我的解决方案。解决方案是:

    find . -type d \( -empty -delete -o -exec sh -c '
       special=".directory"
       test -f "$1/$special" \
       && find "$1" -mindepth 1 -maxdepth 1 ! -name "$special" | { ! grep -q .; } \
       && rm "$1/$special"
    ' find-sh {} \; -delete \) -print
    

    它的工作原理如下:

    • 因为-delete暗示-depth,该命令只有在处理完目录中的所有内容后才会处理目录。这很好,因为我们确实希望它先处理并可能删除更深的子目录,因此当它到达父目录时,它有可能刚刚变为空或几乎为空。

    • 该命令作用于目录类型的文件(-type d)。

    • 如果当前考虑的目录是空的,该命令将尝试删除它(-empty -delete)。

    • 否则(即如果目录不为空),将执行一段 shell 代码。坦白地说,如果目录为空且删除失败,也会执行该代码;但在这种情况下,该代码片段应该是无害的,所以没问题。

      shell 代码使用&&,因此只有当前一步成功时,才会执行下一步。步骤如下:

      • 测试是否存在具有我们的“特殊”名称的常规文件(test -f …)。
      • 开始直接在目录 ( ) 中查找名称不同于“特殊”名称的文件-mindepth 1 -maxdepth 1。如果内部输出find为空,则将grep -q .以非零退出状态退出,因此! grep …将返回成功...
      • 然后rm就会执行删除“特殊”文件的操作。

      只有rm成功了,-exec测试才会被认为是目录的真实测试,并且-delete会尝试最后一次。

    • -print-delete将打印成功(第一个或第二个)的目录的路径名。

    笔记:

    • 在我的测试中,即使它是空的,-delete也没有删除,尽管它正式成功了。.
    • -name采用模式。一般来说,如果“特殊”名称包含*,?或者[,那么您需要调整代码。.directory在这件事上是安全的。
    • 5
  2. Best Answer
    Peter Cordes
    2024-12-07T12:48:42+08:002024-12-07T12:48:42+08:00

    考虑到某些答案的复杂性,我认为 Perl 或 Python 是遍历目录树、获取目录条目列表以及检查它是否完全等于包含 1 个元素的列表.directory(并且它是一个常规文件)的正确工具。

    为每个子目录使用findfork/exec 复杂sh -c命令似乎是一种浪费,我的眼睛都快要看不懂 Kamil 的回答中的逻辑了。假设整个树的递归目录列表很容易放入系统的 RAM 中,那么简单的工具就是最佳选择。

    Perl 具有File::Find深度优先递归功能,这很好,但它希望在每个目录条目上调用回调函数。因此,如果您想要一个目录列表,您必须在此基础上自己完成。虽然不是特别好,但也不理想,所以我研究了 Python。

    Python 的目录遍历标准库函数是os.walk,它是深度优先的。但有趣的是,它生成一个迭代器root, dirs, files(我复制的使用示例),其中后两个是目录内容的列表root,分为目录和非目录文件。这正是我们想要的;或者在深度优先搜索中。

    对于您的用例,删除仅包含其他目录的目录中的文件可能没问题.directory? 如果是这样,我们可以使用 Python 执行此操作,然后使用find -depth -type d -empty -delete (或-print -delete查看我们将删除哪些目录)。

    #!/usr/bin/python
    
    import os
    import sys
    
    if (len(sys.argv) != 2):
        print ("usage: dir-remove path")
        exit(1)       # not really needed; sys[1] errors on its own if there aren't enough args, and I haven't implemented looping over multiple args.  But make sure 
    
    for root, dirs, files in os.walk(sys.argv[1]):
        print (root, dirs, files)
        if (files == [".directory"]):
            # only one non-directory file and it's called .directory
            print("os.unlink " + os.path.join(root, ".directory") )       # debug
            #os.unlink (os.path.join(root, ".directory") )                  # for real
    

    测试设置:

    $ mkdir -p foo/bar/baz
    $ touch foo/bar/baz/.directory  foo/bar/.directory  foo/{a.txt,.directory}
    $ find foo -exec ls -dn {} +
    drwxr-xr-x 3 1000 1000 100 Dec  7 00:35 foo
    -rw-r--r-- 1 1000 1000   0 Dec  7 00:05 foo/a.txt
    drwxr-xr-x 3 1000 1000  80 Dec  7 00:35 foo/bar
    drwxr-xr-x 2 1000 1000  60 Dec  7 00:35 foo/bar/baz
    -rw-r--r-- 1 1000 1000   0 Dec  7 00:35 foo/bar/baz/.directory
    -rw-r--r-- 1 1000 1000   0 Dec  7 00:35 foo/bar/.directory
    -rw-r--r-- 1 1000 1000   0 Dec  7 00:05 foo/.directory
    

    使用方法,调试打印版本:

    ./dir-remove.py /tmp/foo
    /tmp/foo ['bar'] ['a.txt', '.directory']
    /tmp/foo/bar ['baz'] ['.directory']
    os.unlink /tmp/foo/bar/.directory
    /tmp/foo/bar/baz [] ['.directory']
    os.unlink /tmp/foo/bar/baz/.directory
    

    实际用法:运行 Python 脚本删除.directory文件,然后find ... -delete深度优先删除空目录。find如果我想构建更可重用的解决方案,我可以在循环后使用 Python exec。

    $ ./dir-remove.py foo   # with both prints commented, os.unlink uncommented
    $ find foo
    foo/a.txt
    foo/.directory
    foo/bar
    foo/bar/baz
    
    $ find foo -depth -type d -empty -print -delete
    foo/bar/baz
    foo/bar
    

    剩下的就只有foo/a.txt和(当然foo/.directory还有目录本身)。foo

    限制:即使非空,foo/bar/.directory也会被删除foo/bar/baz,但最终并没有被删除。 如果不用 Python 进行深度优先搜索,或者回到 Perl 并使用它自己File::Find列出目录,我认为没有简单的解决方案。

    我只了解一点点 Python,但这仍然很容易实现,并且我依靠标准库来完成繁重的工作,所以希望它应该是强大的。

    • 3
  3. tink
    2024-12-07T06:36:15+08:002024-12-07T06:36:15+08:00

    我不确定我是否完全理解了您的意思,但是这能满足您的要求吗?

    $ find tmp
    tmp/
    tmp/a
    tmp/1
    tmp/1/2
    tmp/1/2/.directory
    tmp/1/2/c
    tmp/1/2/3
    tmp/1/2/3/.directory
    tmp/1/2/3/d
    tmp/1/b
    

    然后运行:

    $ find -depth -empty -name .directory -exec rm -vrf {} \;
    removed directory './tmp/1/2/.directory'
    removed directory './tmp/1/2/3/.directory'
    

    然后会产生:

    $ find tmp/
    tmp/
    tmp/a
    tmp/1
    tmp/1/2
    tmp/1/2/c
    tmp/1/2/3
    tmp/1/2/3/d
    tmp/1/b
    
    • 0

相关问题

  • 如何让我的 Linux 机器看起来像是在运行 Windows?

  • 对于 cp 或 mv,是否有等同于 cd - 的东西?

  • 以 root 身份运行 docker 容器

  • 如何在域和 Linux 活动目录中启用指纹传感器

  • 如何在CentOS 7 中将Ctrl+C 永久更改为Ctrl+K?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何减少“vmmem”进程的消耗?

    • 11 个回答
  • Marko Smith

    从 Microsoft Stream 下载视频

    • 4 个回答
  • Marko Smith

    Google Chrome DevTools 无法解析 SourceMap:chrome-extension

    • 6 个回答
  • Marko Smith

    Windows 照片查看器因为内存不足而无法运行?

    • 5 个回答
  • Marko Smith

    支持结束后如何激活 WindowsXP?

    • 6 个回答
  • Marko Smith

    远程桌面间歇性冻结

    • 7 个回答
  • Marko Smith

    子网掩码 /32 是什么意思?

    • 6 个回答
  • Marko Smith

    鼠标指针在 Windows 中按下的箭头键上移动?

    • 1 个回答
  • Marko Smith

    VirtualBox 无法以 VERR_NEM_VM_CREATE_FAILED 启动

    • 8 个回答
  • Marko Smith

    应用程序不会出现在 MacBook 的摄像头和麦克风隐私设置中

    • 5 个回答
  • Martin Hope
    Vickel Firefox 不再允许粘贴到 WhatsApp 网页中? 2023-08-18 05:04:35 +0800 CST
  • Martin Hope
    Saaru Lindestøkke 为什么使用 Python 的 tar 库时 tar.xz 文件比 macOS tar 小 15 倍? 2021-03-14 09:37:48 +0800 CST
  • Martin Hope
    CiaranWelsh 如何减少“vmmem”进程的消耗? 2020-06-10 02:06:58 +0800 CST
  • Martin Hope
    Jim Windows 10 搜索未加载,显示空白窗口 2020-02-06 03:28:26 +0800 CST
  • Martin Hope
    andre_ss6 远程桌面间歇性冻结 2019-09-11 12:56:40 +0800 CST
  • Martin Hope
    Riley Carney 为什么在 URL 后面加一个点会删除登录信息? 2019-08-06 10:59:24 +0800 CST
  • Martin Hope
    zdimension 鼠标指针在 Windows 中按下的箭头键上移动? 2019-08-04 06:39:57 +0800 CST
  • Martin Hope
    jonsca 我所有的 Firefox 附加组件突然被禁用了,我该如何重新启用它们? 2019-05-04 17:58:52 +0800 CST
  • Martin Hope
    MCK 是否可以使用文本创建二维码? 2019-04-02 06:32:14 +0800 CST
  • Martin Hope
    SoniEx2 更改 git init 默认分支名称 2019-04-01 06:16:56 +0800 CST

热门标签

windows-10 linux windows microsoft-excel networking ubuntu worksheet-function bash command-line hard-drive

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve