Linux find 与 rm 联动删除符合条件的文件

xargs 方法

find . -name 'file*' -size 0 -print0 | xargs -0 rm

首先 find 找到符合条件的文件并输出文件名,然后管道传递给 xargs,然后由 xargs 拼接出结果。

需要注意的是 -print0 的意思是用一个 \0 作为分隔符,是用来配合 xargs 的 -0 (使用\0作为分隔符)使用的。

GUN find 法

find -name 'file*' -size 0 -delete

GUN find 直接支持了 -delete 参数,甚至还有 -ls 参数,可以自动在找到符合要求的文件之后进行删除或列出详细信息的操作。目前大部分 Linux 发行版用的都是 GUN find,所以该方法比较通用。但是如果你的 Linux 发行版中安装的 find 不支持这两个参数,那么就不能使用这个方法了。

find -exec

find . -name file* -exec rm {} \;
find . -name file* -exec rm {} \+

第一行的写法是将找到的文件名拼接到 {} 中,然后执行命令。第二行类似,不同的是把所有文件名拼接成一条命令。也就是说,用方法一,如果 find 的结果是

1
2
3

那么最终就会看到:

rm 1
rm 2
rm 3

这样三个进程。但是使用方法二,则会看到:

rm 1 2 3

只有一个进程,效率更高。

但是需要注意的是,命令参数是有长度限制的,如果文件过多,可能会出现:

cannot execute [Argument list too long]

这是因为参数过多,超过了系统限制。这时候用方法一就能避免这个问题。

Update: 这里说一个 find 命令的小坑。如果想用 find 找到指定大小的文件并删除的话,应该这么写条件:

find ./ -size 100k
find ./ -size 100M
find ./ -size 100G

注意此处是精确匹配。不过可以在数值之前加 +/- 来进行大于或小于的匹配:

find ./ -size +100k #找所有大于 100K 的文件
find ./ -size -100M #找所有小于 100M 的文件
find ./ -size +100G

但是!我上面说的最低的单位都是 K,如果是 Byte 作为单位要怎么办呢?下面两种哪种对?还是都可以?

find ./ -size 100b
find ./ -size 100

实际上,这两种都是错的。来看看实际操作:

➜  test ll
total 8
drwxr-xr-x    3 John  staff   102B May 24 09:53 ./
drwxr-xr-x  118 John  staff   3.9K May 24 09:53 ../
-rw-r--r--    1 John  staff    14B May 24 09:53 test
➜  test find ./ -size 14
➜  test find ./ -size 14b
find: -size: 14b: illegal trailing character
➜  test find ./ -size 14c
.//test
➜  test

可以看出,当单位是 Byte 的时候,正确的写法是用 c 作为单位后缀。具体可见 find 的 man page

       -size n[ckMGTP]
             True if the file's size, rounded up, in 512-byte blocks is n.  If n is followed by a c, then the primary is true if the file's size is n bytes (characters).  Similarly if n is followed by a scale indicator then the file's size is compared to n scaled as:

             k       kilobytes (1024 bytes)
             M       megabytes (1024 kilobytes)
             G       gigabytes (1024 megabytes)
             T       terabytes (1024 gigabytes)
             P       petabytes (1024 terabytes)
       -size n[cwbkMG]
              File uses n units of space.  The following suffixes can be used:

              `b'    for 512-byte blocks (this is the default if no suffix is used)

              `c'    for bytes

              `w'    for two-byte words

              `k'    for Kilobytes (units of 1024 bytes)

              `M'    for Megabytes (units of 1048576 bytes)

              `G'    for Gigabytes (units of 1073741824 bytes)

              The  size  does  not  count indirect blocks, but it does count blocks in sparse files that are not actually allocated.  Bear in mind that the `%k' and `%b' format specifiers of -printf handle sparse files
              differently.  The `b' suffix always denotes 512-byte blocks and never 1 Kilobyte blocks, which is different to the behaviour of -ls.

关于这个默认为什么是 512-byte block,我查了一下相关资料,应该是因为早起在 IBM AIX 系统上 du 的默认单位就是 512-byte block,这是一个 POSIX 标准。这点从 dd 等命令的默认大小也能看出来:

➜  test dd if=/dev/random of=test count=1
1+0 records in
1+0 records out
512 bytes transferred in 0.000074 secs (6905092 bytes/sec)
➜  test ll
total 8
drwxr-xr-x    3 John  staff   102B May 24 09:53 ./
drwxr-xr-x  118 John  staff   3.9K May 24 09:53 ../
-rw-r--r--    1 John  staff   512B May 24 10:02 test

而且在造出了一个刚好 512B 的文件之后,我将其复制一份加了一个字符,达到 515B,然后再来试试 find 命令:

➜  test ll
total 16
drwxr-xr-x    4 John  staff   136B May 24 10:02 ./
drwxr-xr-x  118 John  staff   3.9K May 24 09:53 ../
-rw-r--r--    1 John  staff   512B May 24 10:02 test
-rw-r--r--    1 John  staff   515B May 24 10:02 test2
➜  test find ./ -size 1
./
.//test
➜  test find ./ -size 2
.//test2
➜  test

可以看到,正如文档中描述了,find 会直接向上取整来进行比较,然后返回结果。

CC BY-NC-SA 4.0 Linux find 与 rm 联动删除符合条件的文件 by 桔子小窝 is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

发表评论

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据