Эффективный способ выполнения вычислений в bash

С помощью zshвы можете определить такую ​​функцию, как:

 istext() [[ $(file -b --mime-type -- "${1-$REPLY}") = text/* ]]

Которые затем можно было бы использовать в квалификаторах glob, таких как:

 less -- *(.L+0+istext)

Для просмотра не -пустых(L+0длины больше 0 )обычных файлов(.)в текущем каталоге, которые являются текстовыми в соответствии с file.

6
02.03.2020, 20:51
2 ответа

Пожалуйста, не делайте этого в оболочке. Не существует количества настроек, которые когда-либо сделали бы его удаленно эффективным. Циклы оболочки медленные , и использование оболочки для разбора текста — просто плохая практика. Весь ваш скрипт можно заменить этим простым awkодним -лайнером, который будет работать на порядки быстрее:

awk 'BEGIN{E = exp(1);} $1>0{tot+=log($1); c++} END{m=tot/c; printf "%.2f\n", E^m}' file

Например, если я запускаю это для файла, содержащего числа от 1 до 100, я получаю:

$ seq 100 > file
$ awk 'BEGIN{E = exp(1);} $1>0{tot+=log($1); c++} END{m=tot/c; printf "%.2f\n", E^m}' file
37.99

Что касается скорости, я протестировал ваше решение для оболочки, ваше решение для python и awk, который я указал выше, на файле, содержащем числа от 1 до 10000:

## Shell
$ time foo.sh
3677.54

real    1m0.720s
user    0m48.720s
sys     0m24.733s

### Python
$ time foo.py
The Geometric Mean is:  3680.827182220091

real    0m0.149s
user    0m0.121s
sys     0m0.027s


### Awk
$ time awk 'BEGIN{E = exp(1);} $1>0{tot+=log($1); c++} END{m=tot/c; printf "%.2f\n", E^m}' input.txt
3680.83

real    0m0.011s
user    0m0.010s
sys     0m0.001s

Как видите, awkработает даже быстрее, чем Python, и его намного проще писать. Вы также можете превратить его в сценарий «оболочки», если хотите. Либо вот так:

#!/bin/awk -f

BEGIN{
    E = exp(1);
} 
$1>0{
    tot+=log($1);
    c++;
}
 
END{
    m=tot/c; printf "%.2f\n", E^m
}

или сохранив команду в сценарии оболочки:

#!/bin/sh
awk 'BEGIN{E = exp(1);} $1>0{tot+=log($1); c++;} END{m=tot/c; printf "%.2f\n", E^m}' "$1"
15
28.04.2021, 23:21

Вот несколько советов. Я не могу проверить их, не зная точно, что находится в вашем файле, но я надеюсь, что это поможет. Всегда есть разные, лучшие способы сделать что-то, так что это вовсе не исчерпывающий список.


Изменить условие if

if (( $(echo " "$i" > "0" " | bc -l) )); then

Измените его на:

if [[ "$i" -gt 0 ]]; then

Первая строка создает несколько процессов, даже если она выполняет простую математику. Решение состоит в том, чтобы использовать ключевое слово оболочки [[.


Удалить ненужный код

else
  total="$total"

По сути, это способ явно тратить время на ничегонеделание :). Эти 2 строки можно удалить сразу.

0
28.04.2021, 23:21

Теги

Похожие вопросы