Можно ли ускорить этот сценарий оболочки?

У меня есть задача создать скрипт, который принимает на вход огромный текстовый файл. Затем необходимо найти все слова и количество вхождений и создать новый файл, в каждой строке которого отображается уникальное слово и его вхождение.

В качестве примера возьмем файл с таким содержимым:

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

Как видите, он работал за 7,23 с по сравнению со сценарием оболочки, который выполнялся за 16,17 с . Я пытался работать с большими файлами, и Python всегда побеждал. У меня есть несколько вопросов к senario выше:

  1. Почему скрипт Python быстрее, учитывая, что команды оболочки написаны на C? Я понимаю, что сценарий оболочки может быть не оптимальным.
  2. Как я могу улучшить сценарий оболочки?
  3. Могу ли я улучшить скрипт Python?

Чтобы было ясно, я не сравниваю Python со сценариями оболочки. Я не пытаюсь начать флейм или мне не нужны ответы на каком-либо другом языке, сравнивая себя с тем, чтобы быть быстрее. Используя философию UNIX по передаче небольших команд для выполнения задачи, как мне ускорить сценарий оболочки?

13
задан satran 16 August 2012 в 14:27
поделиться