Tengo la tarea de crear un script que toma un gran archivo de texto como entrada. Luego necesita encontrar todas las palabras y el número de ocurrencias y crear un nuevo archivo con cada línea mostrando una palabra única y su ocurrencia.¿Es posible hacer este script de shell más rápido?
Como ejemplo tener un archivo con este contenido:
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.
Necesito crear un archivo que se parece a esto:
1 AD
1 ADIPISICING
1 ALIQUA
...
1 ALIQUIP
1 DO
2 DOLOR
2 DOLORE
...
Por esta Escribí un guión usando tr
, sort
y 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
¿Qué hacer? es se divide las palabras por espacio como el delimitador. Si la palabra contiene -_?!.;:
los rompo en palabras de nuevo. Elimino las puntuaciones, los caracteres especiales y los dígitos y convierto toda la cadena en mayúscula. Una vez hecho esto, lo ordeno y lo paso por uniq
para que llegue al formato que quiero.
Ahora descargué la Biblia en formato txt y la usé como entrada. Timing esto que tengo:
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
Hice lo mismo con una secuencia de comandos de 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')
Cuando ejecuta la secuencia de comandos que tengo:
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
Como se puede ver que corría en 7.23s en comparación con el script de shell que se ejecutó en 16.17s. Lo he intentado con archivos más grandes y siempre Python parece triunfar. Tengo algunas preguntas para el senario de arriba:
- ¿Por qué es más rápido el guión de Python dado que los comandos de la shell están escritos en C? Me doy cuenta de que el script de shell puede no ser el óptimo.
- ¿Cómo puedo mejorar el script de shell?
- ¿Puedo mejorar el script de Python?
Para ser claros, no estoy comparando Python con los scripts de shell. No estoy tratando de iniciar una guerra de llama o no necesito respuestas en cualquier otro idioma comparándose para ser más rápido. Utilizando la filosofía de UNIX de conectar comandos pequeños para hacer una tarea, ¿cómo hago que el script de shell sea más rápido?
yo sugeriría cambiar el título a algo así como " ¿Es posible hacer este script de shell más rápido? ", Usando el script de python tan diferente y como punto de comparación. Esto eliminaría el riesgo de discusiones inútiles y fuera de tema sobre las diferencias entre python y shell. –
No creo que la filosofía \ * nix de usar muchos comandos pequeños que hacen bien una sola tarea esté en su lugar porque es más * eficiente *. La razón por la que está en su lugar es porque con las herramientas que tenemos, puede lograr mucho y ahorrarse mucho tiempo desarrollando un nuevo programa para una tarea simple. – mgilson
Python está escrito en C, también. Estar "escrito en C" no es suficiente para acelerar las cosas: las capas intermedias (y todas las líneas de lectura/escritura desde y hacia las tuberías) tienen una sobrecarga. –