查找使用 inode 的位置

phe*_*mer 220 filesystems inode

所以我在我们的一个机器上收到了来自我们的监控系统的警告,文件系统上的空闲 inode 数量越来越少。

df -i 输出显示:

Filesystem       Inodes  IUsed    IFree IUse% Mounted on
/dev/xvda1       524288 422613   101675   81% /
Run Code Online (Sandbox Code Playgroud)

如您所见,根分区使用了 81% 的 inode。
我怀疑它们都在一个目录中使用。但是我怎样才能找到它的位置呢?

phe*_*mer 254

我在 stackoverflow 上看到了这个问题,但我不喜欢任何答案,无论如何,这确实是一个应该出现在 U&L 上的问题。

基本上,文件系统上的每个文件都使用一个 inode。所以用完 inode 通常意味着你有很多小文件。所以问题真的变成了,“哪个目录中有大量文件?”

在这种情况下,我们关心的文件系统是根文件系统/,因此我们可以使用以下命令:

{ find / -xdev -printf '%h\n' | sort | uniq -c | sort -k 1 -n; } 2>/dev/null
Run Code Online (Sandbox Code Playgroud)

这将转储文件系统上每个目录的列表,并以该目录中的文件(和子目录)的数量为前缀。因此,文件数最多的目录将位于底部。

就我而言,结果如下:

   1202 /usr/share/man/man1
   2714 /usr/share/man/man3
   2826 /var/lib/dpkg/info
 306588 /var/spool/postfix/maildrop
Run Code Online (Sandbox Code Playgroud)

所以基本上/var/spool/postfix/maildrop是消耗所有的inode。

*注意,这个答案确实有我能想到的三个警告。它无法正确处理路径中包含换行符的任何内容。我知道我的文件系统没有带换行符的文件,并且由于这仅用于人类消费,因此潜在问题不值得解决,并且可以随时替换上述and命令的\nwith\0和 use-z选项,如下所示:sortuniq

{ find / -xdev -printf '%h\0' |sort -z |uniq -zc |sort -zk1rn; } 2>/dev/null
Run Code Online (Sandbox Code Playgroud)

您可以选择添加head -zn10到命令中以获取前 10 个最常用的 inode。

如果文件分散在大量目录中,它也不会处理。但这不太可能,所以我认为风险是可以接受的。它还会多次计算指向同一文件的硬链接(因此仅使用一个 inode)。同样,不太可能给出误报*


我不喜欢 stackoverflow 答案中的任何答案的关键原因是它们都跨越了文件系统边界。由于我的问题出在根文件系统上,这意味着它会遍历每个挂载的文件系统。抛出-xdevfind 命令甚至无法正常工作。
例如,最受欢迎的答案是这个:

for i in `find . -type d `; do echo `ls -a $i | wc -l` $i; done | sort -n
Run Code Online (Sandbox Code Playgroud)

如果我们将其改为

for i in `find . -xdev -type d `; do echo `ls -a $i | wc -l` $i; done | sort -n
Run Code Online (Sandbox Code Playgroud)

即使/mnt/foo是一个挂载,它也是根文件系统上的一个目录,所以它会出现在 中find . -xdev -type d,然后它会被传递到ls -a $i,它会潜入到挂载中。

find在我的答案,而不是列出在安装每一个文件的目录。所以基本上有一个文件结构,例如:

/foo/bar
/foo/baz
/pop/tart
Run Code Online (Sandbox Code Playgroud)

我们最终得到

/foo
/foo
/pop
Run Code Online (Sandbox Code Playgroud)

所以我们只需要计算重复行的数量。

  • 使用绑定挂载是避免搜索其他文件系统的更可靠方法,因为它允许访问挂载点下的文件。例如,假设我在 `/tmp` 下创建了 300,000 个文件,然后系统被配置为在 `/tmp` 上挂载一个 tmpfs。那么你将无法单独使用“find”找到文件。不太可能,但值得注意。 (7认同)
  • @MohsenPahlevanzadeh 这不是我的答案的一部分,我正在评论为什么我不喜欢该解决方案,因为它是这个问题的常见答案。 (3认同)
  • 这两项工作都必须删除排序,因为排序需要在输出足够大时创建一个文件,这是不可能的,因为我达到了 100% 的 inode 使用率。 (2认同)
  • 请注意,“-printf”似乎是一个需要查找的 GNU 扩展,因为 OS X 中可用的 BSD 版本不支持它。 (2认同)

mik*_*erv 31

这是在提问者的要求下从这里重新发布的:

du --inodes --separate-dirs | sort -rh | sed -n \
        '1,50{/^.\{71\}/s/^\(.\{30\}\).*\(.\{37\}\)$/\1...\2/;p}'
Run Code Online (Sandbox Code Playgroud)

如果你想留在同一个文件系统中,你可以:

du --inodes --one-file-system --separate-dirs
Run Code Online (Sandbox Code Playgroud)

这是一些示例输出:

15K     /usr/share/man/man3
4.0K    /usr/lib
3.6K    /usr/bin
2.4K    /usr/share/man/man1
1.9K    /usr/share/fonts/75dpi
...
519     /usr/lib/python2.7/site-packages/bzrlib
516     /usr/include/KDE
498     /usr/include/qt/QtCore
487     /usr/lib/modules/3.13.6-2-MANJARO/build/include/config
484     /usr/src/linux-3.12.14-2-MANJARO/include/config
Run Code Online (Sandbox Code Playgroud)

现在与 LS:

请注意,以上需要 GNU du(即来自 GNU coreutils),因为 POSIXdu不支持 --inodes,--one-file-system或 --separate-dirs。(如果你有Linux的,你可能有GNU的coreutils。如果你有GNU du,可以缩写--one-file-system到 -x(小写),并 --separate-dirs以 -S(大写)。POSIX du识别 -x,但不能 -S或任何长选项。)一些人提到他们不这样做拥有最新的 coreutils 并且该--inodes选项对他们不可用。(但它出现在 GNU coreutils 8.22 版中;如果您的版本比那个旧,您可能应该升级。)所以,这里是ls

ls ~/test -AiR1U |
    sed -rn '/^[./]/{h;n;}; G;
        s|^ *([0-9][0-9]*)[^0-9][^/]*([~./].*):|\1:\2|p' |
    sort -t : -uk1.1,1n |
    cut -d: -f2 | sort -V |
    uniq -c | sort -rn | head -n10
Run Code Online (Sandbox Code Playgroud)

如果您很好奇,那么乏味的正则表达式的核心是将每个ls递归搜索结果中的文件名替换为找到它的目录名。从那里开始,只需压缩重复的 inode 编号,然后计算重复的目录名称并相应地排序。

-U选项与在它专门针对排序特别有用排序,而是提出在原来的顺序目录列表 – 或者,换句话说,通过 inode 编号.

当然,-A对于(几乎)所有,-i对于 inode 和-R递归,这就是它的长处和短处。在 -1 (1)选项被列入的习惯势力了。

对此的基本方法是,我将 ls 的每个文件名替换为其在 sed 中的包含目录名。从那以后......好吧,我自己有点模糊。我相当确定它正在准确计算文件,正如您在此处看到的:

% _ls_i ~/test
  100 /home/mikeserv/test/realdir
    2 /home/mikeserv/test
    1 /home/mikeserv/test/linkdir
Run Code Online (Sandbox Code Playgroud)

(其中_ls_i代表上述ls- sed-... 管道,定义为别名或脚本)。

这为我提供了与du命令几乎相同的结果:

杜:

15K     /usr/share/man/man3
4.0K    /usr/lib
3.6K    /usr/bin
2.4K    /usr/share/man/man1
1.9K    /usr/share/fonts/75dpi
1.9K    /usr/share/fonts/100dpi
1.9K    /usr/share/doc/arch-wiki-markdown
1.6K    /usr/share/fonts/TTF
1.6K    /usr/share/dolphin-emu/sys/GameSettings
1.6K    /usr/share/doc/efl/html
Run Code Online (Sandbox Code Playgroud)

LS:

14686   /usr/share/man/man3:
4322    /usr/lib:
3653    /usr/bin:
2457    /usr/share/man/man1:
1897    /usr/share/fonts/100dpi:
1897    /usr/share/fonts/75dpi:
1890    /usr/share/doc/arch-wiki-markdown:
1613    /usr/include:
1575    /usr/share/doc/efl/html:
1556    /usr/share/dolphin-emu/sys/GameSettings:
Run Code Online (Sandbox Code Playgroud)

如果您逐行比较乏味地比较上面的内容,您会注意到du输出的第 8 行是/usr/share/fonts/TTF (1.6K),而ls输出的第 8 行是/usr/include (1613)。我认为这include取决于程序首先查看哪个目录——因为它们是相同的文件并且是硬链接的。有点像上面的东西。不过我可能是错的——我欢迎纠正......

杜演示

% du --version
du (GNU coreutils) 8.22
Run Code Online (Sandbox Code Playgroud)

创建一个测试目录:

% mkdir ~/test ; cd ~/test
% du --inodes --separate-dirs
1       .
Run Code Online (Sandbox Code Playgroud)

一些儿童目录:

% mkdir ./realdir ./linkdir
% du --inodes --separate-dirs
1       ./realdir
1       ./linkdir
1       .
Run Code Online (Sandbox Code Playgroud)

制作一些文件:

% printf 'touch ./realdir/file%s\n' `seq 1 100` | . /dev/stdin
% du --inodes --separate-dirs
101     ./realdir
1       ./linkdir
1       .
Run Code Online (Sandbox Code Playgroud)

一些硬链接:

% printf 'n="%s" ; ln ./realdir/file$n ./linkdir/link$n\n' `seq 1 100` | 
    . /dev/stdin
% du --inodes --separate-dirs
101     ./realdir
1       ./linkdir
1       .
Run Code Online (Sandbox Code Playgroud)

查看硬链接:

% cd ./linkdir
% du --inodes --separate-dirs
101

% cd ../realdir
% du --inodes --separate-dirs
101
Run Code Online (Sandbox Code Playgroud)

它们是单独计算的,但是向上一级目录...

% cd ..
% du --inodes --separate-dirs
101     ./realdir
1       ./linkdir
1       .
Run Code Online (Sandbox Code Playgroud)

然后我从下面运行我的运行脚本:

100     /home/mikeserv/test/realdir
100     /home/mikeserv/test/linkdir
2       /home/mikeserv/test
Run Code Online (Sandbox Code Playgroud)

以及格雷姆对类似问题的回答的输出:

101 ./realdir
101 ./linkdir
3 ./
Run Code Online (Sandbox Code Playgroud)

所以我认为这表明计算 inode 的唯一方法是通过 inode。并且因为计算文件意味着计算 inode,所以您不能重复计算 inode - 要准确计算文件 inode 不能计算多次。

  • 哪个版本添加了`--inode`?哪些“变体”/“风味”/“posix-wannabes”/“实现”/有什么? (2认同)

小智 8

我发现使用以下命令可以更快、更轻松地进行深入研究:

$ sudo du -s --inodes * | sort -rn

170202  var
157325  opt
103134  usr
53383   tmp
<snip>
Run Code Online (Sandbox Code Playgroud)

然后您可以进入var例如并查看使用目录的大 inode 在那里。


slm*_*slm 7

我使用了来自 SO Q&A 的答案,标题为:我所有的 inode 都在哪里使用?当我们的 NAS 在大约 2 年前用完时:

$ find . -type d -print0 \
    | while IFS= read -rd '' i; do echo $(ls -a "$i" | wc -l) "$i"; done \
    | sort -n
Run Code Online (Sandbox Code Playgroud)

例子

$ find . -type d -print0 \
    | while IFS= read -rd '' i; do echo $(ls -a "$i" | wc -l) "$i"; done \
    | sort -n
...
110 ./MISC/nodejs/node-v0.8.12/out/Release/obj.target/v8_base/deps/v8/src
120 ./MISC/nodejs/node-v0.8.12/doc/api
123 ./apps_archive/monitoring/nagios/nagios-check_sip-1.3/usr/lib64/nagios
208 ./MISC/nodejs/node-v0.8.12/deps/openssl/openssl/doc/crypto
328 ./MISC/nodejs/node-v0.8.12/deps/v8/src
453 ./MISC/nodejs/node-v0.8.12/test/simple
Run Code Online (Sandbox Code Playgroud)

检查设备的 inode

根据您的 NAS,它可能无法提供功能齐全的df命令。因此,在这些情况下,您可以改用使用tune2fs

$ sudo tune2fs -l /dev/sda1 |grep -i inode
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype needs_recovery extent flex_bg sparse_super huge_file uninit_bg dir_nlink extra_isize
Inode count:              128016
Free inodes:              127696
Inodes per group:         2032
Inode blocks per group:   254
First inode:              11
Inode size:           128
Journal inode:            8
Journal backup:           inode blocks
Run Code Online (Sandbox Code Playgroud)

跨越文件系统边界

您可以使用-xdev开关直接find将搜索范围缩小到您正在启动搜索的设备。

例子

假设我的/home目录通过我的 NAS 中的 NFS 共享自动挂载,它的名字是 mulder。

$ df -h /home/sam 
Filesystem            Size  Used Avail Use% Mounted on
mulder:/export/raid1/home/sam
                      917G  572G  299G  66% /home/sam
Run Code Online (Sandbox Code Playgroud)

请注意,挂载点仍被视为系统本地。

$ df -h /home/ .
Filesystem            Size  Used Avail Use% Mounted on
-                        0     0     0   -  /home
/dev/mapper/VolGroup00-LogVol00
                      222G  159G   52G  76% /
Run Code Online (Sandbox Code Playgroud)

现在当我发起find

$ find / -xdev  | grep '^/home'
/home
Run Code Online (Sandbox Code Playgroud)

它找到/home但没有自动安装的内容,因为它们在不同的设备上!

文件系统类型

您可以使用切换到find,-fstype来控制find将查看哪种类型的文件系统。

   -fstype type
          File is on a filesystem of type type.  The valid filesystem types 
          vary among different versions of Unix; an incomplete list of 
          filesystem  types that are accepted on some version of Unix or 
          another is: ufs, 4.2, 4.3, nfs, tmp, mfs, S51K, S52K.  You can use 
          -printf with the %F directive to see the types of your
          filesystems.
Run Code Online (Sandbox Code Playgroud)

例子

我有什么文件系统?

$ find . -printf "%F\n" | sort -u
ext3
Run Code Online (Sandbox Code Playgroud)

所以你可以用它来控制交叉:

只有 ext3

$ find . -fstype ext3 | head -5
.
./gdcm
./gdcm/gdcm-2.0.16
./gdcm/gdcm-2.0.16/Wrapping
./gdcm/gdcm-2.0.16/Wrapping/CMakeLists.txt
Run Code Online (Sandbox Code Playgroud)

只有 nfs

$ find . -fstype nfs | head -5
$ 
Run Code Online (Sandbox Code Playgroud)

ext3 和 ext4

$ find . -fstype ext3 -o -fstype ext4 | head -5
.
./gdcm
./gdcm/gdcm-2.0.16
./gdcm/gdcm-2.0.16/Wrapping
./gdcm/gdcm-2.0.16/Wrapping/CMakeLists.txt
Run Code Online (Sandbox Code Playgroud)


Ash*_*rpe 5

查找使用的 inode 的命令:

for i in /*; do echo $i; find $i |wc -l | sort ; done
Run Code Online (Sandbox Code Playgroud)