我的任务是创建一个以巨大文本文件作为输入的脚本。然后它需要查找所有单词和出现次数,并创建一个新文件,每行显示一个唯一单词及其出现次数。
以一个包含以下内容的文件为例:
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt
mollit anim id est laborum.
我需要创建一个如下所示的文件:
1 AD
1 ADIPISICING
1 ALIQUA
...
1 ALIQUIP
1 DO
2 DOLOR
2 DOLORE
...
为此,我使用tr
,sort
和编写了一个脚本uniq
:
#!/bin/sh
INPUT=$1
OUTPUT=$2
if [ -a $INPUT ]
then
tr '[:space:][\-_?!.;\:]' '\n' < $INPUT |
tr -d '[:punct:][:special:][:digit:]' |
tr '[:lower:]' '[:upper:]' |
sort |
uniq -c > $OUTPUT
fi
这样做是用空格分隔单词作为分隔符。如果单词包含-_?!.;:
,我将它们再次分解成单词。我删除了标点符号、特殊字符和数字,并将整个字符串转换为大写。完成此操作后,我对其进行排序并传递它uniq
以使其成为我想要的格式。
现在我下载了txt格式的圣经并将其用作输入。我得到了这个时机:
scripts|$ time ./text-to-word.sh text.txt b
./text-to-word.sh text.txt b 16.17s user 0.09s system 102% cpu 15.934 total
我对 Python 脚本做了同样的事情:
import re
from collections import Counter
from itertools import chain
import sys
file = open(sys.argv[1])
c = Counter()
for line in file.readlines():
c.update([re.sub('[^a-zA-Z]', '', l).upper()
for l in chain(*[re.split('[-_?!.;:]', word)
for word in line.split()])])
file2 = open('output.txt', 'w')
for key in sorted(c):
file2.write(key + ' ' + str(c[key]) + '\n')
当我执行脚本时,我得到:
scripts|$ time python text-to-word.py text.txt
python text-to-word.py text.txt 7.23s user 0.04s system 97% cpu 7.456 total
如您所见,与运行在16.17s中的 shell 脚本相比,它在7.23s中运行。我尝试过使用更大的文件,并且 Python 似乎总是获胜。我对上面的 senario 有几个问题:
- 鉴于 shell 命令是用 C 编写的,为什么 Python 脚本更快?我确实意识到 shell 脚本可能不是最佳脚本。
- 如何改进 shell 脚本?
- 我可以改进 Python 脚本吗?
需要明确的是,我不是将 Python 与 shell 脚本进行比较。我不是想开始一场激烈的战争,也不需要任何其他语言的答案来比较自己更快。使用 UNIX 管道小命令来完成任务的哲学,我如何使 shell 脚本更快?