意外地将数百万个文件写入(但随后删除)目录后,Bash 选项卡完成速度缓慢

意外地将数百万个文件写入(但随后删除)目录后,Bash 选项卡完成速度缓慢

有一天,我遇到了一个脚本错误,将 400 万个小文本文件写入了我的主目录:

我意外地将 400 万个小文本文件写入了一个文件夹,如何最好地删除它们?

我删除了这些文件,但从那时起,每当我点击选项卡来完成文件名或路径时,在发生任何事情之前都会有半秒的延迟。

虽然这些文件现在已被删除,但我认为 gpt 或类似的文件会受到一些持久的损坏?有什么有用的工具可以用来清理这个吗?

文件系统是 ext4(RAID 1 中的两个 3TB 驱动器),我运行的是 CentOS 7。

% ls -ld "$HOME"
drwx------. 8 myname myname 363606016 Nov 18 09:21 /home/myname 

谢谢

答案1

正如评论中提到的,您的主目录本身很大,并且不会再缩小。扫描主目录的内容将涉及每次读取大量数据(从缓存或磁盘)。

要解决此问题,您需要重新创建主目录:

  • 注销,以 root 身份登录,并确保没有正在运行的进程引用您的主目录:

    lsof /home/myname
    
  • 复制您的主目录:

    cd /home
    cp -al myname myname.new
    
  • 重命名你的主目录:

    mv myname myname.old
    
  • 重命名您的新主目录:

    mv myname.new myname
    

您现在可以重新登录。您闪亮的新主目录将仅占用它真正需要的空间,并且文件操作应该与您期望的一样快。cp -al确保新目录下的所有文件都可用,但它使用硬链接,以便不占用额外空间(除了目录结构之外)。由于存在硬链接,对其中一个目录中的文件所做的任何更改都会反映在另一个目录中,但您可以安全地删除myname.old.

类似的方法可用于任何曾经包含大量文件的目录,尽管在大多数其他情况下您不需要先注销。

答案2

正如另一个答案中提到的,如果您可以轻松地重新创建目录,那么这可以在不关闭系统的情况下完成。

在其他情况下,目录树中的文件数量或大小使得将它们复制到新目录变得更加困难,您还可以卸载文件系统(如果是根文件系统,则从救援磁盘启动)并e2fsck -fD /dev/sdX运行文件系统来优化目录(-D选项)。这会将目录条目打包到最少数量的块中,而不复制文件数据。

答案3

斯蒂芬·基特的回答基本上是正确的方法,但应该使用mv而不是完成cp- 无需花费几分钟或几个小时复制所有文件,因为移动它们几乎不需要时间。例如:

  1. 以您的用户身份注销(所有登录实例,包括任何 ssh 会话)并以 root 身份登录。

    如果您的系统配置为阻止直接 root 登录(例如,因为 root 的密码被禁用),请以 root 身份登录不同的用户(如果需要,创建一个并授予其访问su或 的权限sudo),然后获取 root shell。

  2. 无需确保您的用户没有运行任何程序或您的主目录下有打开的文件因为文件句柄(和索引节点号)不会改变除非您的主目录有自己的专用文件系统(例如, if/home/username是它自己的安装点,而不仅仅是 的子目录/home)。

    实际的移动(在下面的步骤 3 中)应该只需要几分之一秒(取决于您的主目录顶层的文件和目录的数量。这就是需要移动的所有内容),因为它是mv,而不是cp- 没有数据被复制,这一切都通过重命名很快完成。

    在这么短的时间内,任何东西都不太可能创建新文件(或尝试打开尚未移动的文件)。

    然而,如果你是偏执狂,或者是可能cron或工作等可以做到这一点at,然后暂时禁用它们。请记住之后重新启动它们。

    对于任何其他可能执行此操作的正在运行的进程(例如 NFS 或 samba 或邮件传递或 ftpd 或其他任何进程)也是如此 - 现在杀死它们并稍后重新启动它们。顺便说一句,您可以使用例如 来终止所有用户拥有的进程pkill -u username

  3. mv将主目录中的所有内容复制到新的主目录中。例如,如果您的主目录是/home/username,请以 root 身份运行以下命令:

    cd /home
    mv username username.old
    mkdir username
    
    # move the files and subdirectories to the new home
    # BTW, using `find` ensures that "hidden" dotfiles and dotdirs are moved
    # along with the non-hidden files & dirs.
    cd username.old
    find . -mindepth 1 -maxdepth 1 -exec mv {} ../username/ +
    cd ..
    
    # fix ownership and perms of the new home dir
    gid="$(getent passwd username | cut -d: -f4)"
    perms="$(stat --printf "%a" username.old)"
    chown "username:$gid" username
    chmod "$perms" username
    
    rmdir username.old
    

注意:stat --printf ...以上需要 GNU stat。你说你正在运行 Centos 7,所以这就是你所拥有的。

对于在非 GNU 系统上遇到类似问题的任何人,您必须找到其他方法来复制权限。 FreeBSD 的版本stat具有类似的功能,但选项不同。或者只是手动在新目录上设置权限 - 它们最有可能是775or 755(可能使用 set-gid,so2775或),但请使用or或其他方式2755进行验证。ls -ldstat

相关内容