我想列出/usr/
使用中的所有文件ls
。我不是ls
直接打电话,而是通过xargs
。此外,我正在使用xargs
参数-L
并-P
利用我的所有核心。
find /usr/ -type f -print0 | xargs -0 -L16 -P4 ls -lAd | sort -k9 > /tmp/aaa
上面的命令按预期工作。它产生很好的输出。但是,当我将行数参数-L
从 16 增加到 64 时:
find /usr/ -type f -print0 | xargs -0 -L64 -P4 ls -lAd | sort -k9 > /tmp/bbb
结果输出全是乱码。我的意思是,输出不再从新行开始,新行从“上一行”的中间开始,并且全部混合在一起:
-rw-r--r-- 1 root root 5455 Nov 16 2010 /usr/shareonts/X11/encodings/armscii-8.enc.gz
-rw-r--r-- 1 root root 1285 May 29 2016-rw-r--r-- 1 root root 6205 May 29 2016 /usr/include/arpa/nameser_compat.h
-rw-r--r-- 1 root root 0 Apr 17 20-rw-r--r-- 1 root root 933 Apr 16 2012 /usr/share/icons/nuoveXT2/16x16/actions/address-book-new.png
-rw-r--r-- 1 root root 53651 Jun 17 2012-rw-r--r-- 1 root root 7117 May 29 2016 /usr/include/dlfcn.h
-rw-r--r-- 1 root root 311 Jun 9 2015-rw-r--r-- 1 root root 1700 Jun 9 2015 /usr/share/cups/templates/de/add-printer.tmpl
-rw-r--r-- 1 root root 5157 M1 root root 10620 Jun 14 2012 /usr/lib/perl5/Tk/pTk/tkIntXlibDecls.m
-rw-r--r-- 1 root -rwxr-xr-x 1 root root 1829 Jan 22 2013 /usr/lib/emacsen-common/packages/install/dictionaries-common
-rw-r--r-- 1 root r-rw-r--r-- 1 root root 1890 Jun 2 2012 /usr/share/perl5/Date/Manip/TZ/afaddi00.pm
-rw-r--r-- 1 root root 1104 Jul-rw-r--r-- 1 root root 10268 Jul 27 15:58 /usr/share/perl/5.14.2/B/Debug.pm
-rw-r--r-- 1 root root 725 Apr 1-rw-r--r-- 1 root root 883 Apr 1 2012 /usr/share/icons/gnome/16x16/actions/address-book-new.png
有趣的是,它只在使用-L64
或更大时发生。我没有看到这个问题-L16
。
有人能解释一下这里发生了什么吗?
答案1
这与写入管道有关。您正在-L16
为每 16 个文件运行一个进程,这会产生大约一千个字符,具体取决于文件名的长度。和-L64
你在一起的大约有四千人。该ls
程序几乎肯定使用了 stdio 库,并且几乎肯定使用 4kB 缓冲区进行输出,以减少写入调用的次数。
因此 find 会生成大量文件名,然后(对于 -L64 情况)xargs 将它们分成 64 个文件名,并启动 4 个ls
进程来处理它们。每个ls
都会生成其前 4k 输出并将其写入管道进行排序。请注意,此 4k 通常会不是以换行符结束。所以说第三个ls
首先准备好它的第一个 4kB,然后结束
lrwxrwxrwx 1 root root 6 Oct 21 2013 bzegrep -> bzgrep
-rwxr-xr-x 1 root root 4877 Oct 21 2013 bzexe
lrwxrwxrwx 1 root root 6 Oct 2
然后第一个 ls 输出一些内容,例如
total 123459
那么排序的输入将包括lrwxrwxrwx 1 root root 6 Oct 2total 123459
在这种-L16
情况下,ls
进程(通常)只会一次性输出一组完整的结果。
当然,对于这种情况,使用 xargs 和 ls 只是浪费时间和资源,您应该只输出find
已有的信息,而不是运行额外的程序来再次发现信息。
答案2
GNU Parallel 的构建是为了精确解决混合问题(运行时间 40 秒):
find /usr/ -type f -print0 | parallel -0 -L64 -P4 ls -lAd | sort -k9 > /tmp/bbb
它甚至可以检测核心数量(运行时间 40 秒):
find /usr/ -type f -print0 | parallel -0 -L64 ls -lAd | sort -k9 > /tmp/bbb
并均匀地分割输入(运行时间 24 秒):
find /usr/ -type f -print0 | parallel -0 -X ls -lAd | sort -k9 > /tmp/bbb