5

我正在参加 UNIX 入门课程,并且有一个家庭作业问题如下:

上一题有多少个文件是文本文件?文本文件是包含人类可读内容的任何文件。(技巧题。对文件运行 file 命令以查看该文件是文本文件还是二进制数据文件!如果您只是计算带有.txt扩展名的文件的数量,您将不会获得此问题的分数。)

上一个问题只是问有多少个常规文件,这很容易通过find . -type f | wc -l.

我只是无法确定“人类可读的内容”是什么,因为我假设它意味着除了二进制/汇编之外的任何东西,但我认为这就是-type f显示的内容。也许这就是教授所说的“技巧问题”的意思?

这个问题稍后有一个跟进,它还询问“哪些文本文件包含大小写混合的字符串“csc”?”。显然“文本”不仅仅是指.txt文件,但我需要弄清楚第一个问题来确定这一点!

4

2 回答 2

6

为了清楚起见,添加了引号:

对文件运行“file”命令,查看该文件是文本文件还是二进制数据文件!

file命令将检查文件并告诉您它们看起来是什么类型的文件。“文本”一词将(几乎)始终出现在文本文件的描述中。

例如:

desktop.ini:   Little-endian UTF-16 Unicode text, with CRLF, CR line terminators
tw2-wasteland.jpg: JPEG image data, JFIF standard 1.02

所以第一部分是要求你运行file命令并解析它的输出。

我只是无法确定“人类可读的内容”是什么,因为我假设它意味着除了二进制/汇编之外的任何东西,但我认为这就是 -type f 显示的内容。

find -type f查找文件。它过滤掉其他文件系统对象,如目录、符号链接和套接字。但是,它将匹配任何类型的文件:二进制文件、文本文件等。

也许这就是教授所说的“技巧问题”的意思?

听起来他只是在说不要做find -name '*.txt'或一些类似的命令来查找文本文件。不要假设特定的文件扩展名。文件扩展名在 UNIX 中的意义远小于在 Windows 中的意义。很多文件甚至没有文件扩展名!


我在想教授希望我们能够对所有文件运行文件命令并计算其中包含“文本”的文件的数量。

多部分答案怎么样?我将在#1 中给出简单的解决方案,这可能是您的教授正在寻找的。如果您有兴趣,我会解释它的缺点以及如何改进它。

  1. 一种方法是使用xargs,如果您已经了解的话。xargs运行另一个命令,使用来自标准输入的数据作为该命令的参数。

    $ find . -type f | xargs file
    ./netbeans-6.7.1.desktop: ASCII text
    ./VMWare.desktop:         a /usr/bin/env xdg-open script text executable
    ./VMWare:                 cannot open `./VMWare' (No such file or directory)
    (copy).desktop:           cannot open `(copy).desktop' (No such file or directory)
    ./Eclipse.desktop:        a /usr/bin/env xdg-open script text executable
    
  2. 这样可行。有点。对于家庭作业来说已经足够了。但对于现实世界的脚本来说还不够好。

    注意它是如何破坏文件的VMWare (copy).desktop,因为它有一个空格。这是由于xargs' 在空格上拆分参数的默认行为。我们可以通过使用xargs -0在 NUL 字符而不是空格上拆分命令参数来解决此问题。文件名不能包含 NUL 字符,因此这将能够处理任何内容。

    $ find . -type f -print0 | xargs -0 file
    ./netbeans-6.7.1.desktop: ASCII text
    ./VMWare.desktop:         a /usr/bin/env xdg-open script text executable
    ./VMWare (copy).desktop:  a /usr/bin/env xdg-open script text executable
    ./Eclipse.desktop:        a /usr/bin/env xdg-open script text executable
    
  3. 这对于制作脚本来说已经足够好了,而且您会经常遇到这种情况。但我个人更喜欢不需要管道的替代语法,因此效率更高。

    $ find . -type f -exec file {} \;
    ./netbeans-6.7.1.desktop: ASCII text
    ./VMWare.desktop:         a /usr/bin/env xdg-open script text executable
    ./VMWare (copy).desktop:  a /usr/bin/env xdg-open script text executable
    ./Eclipse.desktop:        a /usr/bin/env xdg-open script text executable
    

    要理解这一点,请反复-exec调用,用它找到的每个文件名替换。分号表示命令的结束。file{}\;file

于 2012-09-29T15:34:47.560 回答
0

有一种很好且简单的方法可以确定文件是否是人类可读的文本文件,只需使用file --mime-type <filename>并查找'text/plain'. 无论文件是否具有结尾或与 .txt 不同的结尾,它都会起作用

所以你会这样做:

FILES=`find $YOUR_DIR -type f`

for file in $FILES ;
do

mime=`/usr/bin/file --mime-type $YOUR_DIR/$file | /bin/sed 's/^.* //'`

if [ $mime = "text/plain" ];  then      
    fileTotal=$(( fileTotal + 1 ))
    echo "$fileTotal - $file"
fi

done

echo "$fileTotal human readable files found!"

并且输出会是这样的:

1 - /sampledir/samplefile
2 - /sampledir/anothersamplefile
....
23 human readable files found!

如果您想进一步了解更多人类可读的 mime 类型(例如 HTML 和/或 XML 是否计数?)请查看http://www.feedforall.com/mime-types.htm

于 2012-10-01T06:38:55.863 回答