скорость манипуляции колонны bash против конвейера

У меня есть файл, заполненный контрольными суммами md5 и именами файлов. Мне нужно выполнить некоторую обработку в каждой строке, поэтому мне нужно знать:

  • Какая контрольная сумма
  • Какое имя файла

и действовать соответственно. То есть мне нужно вылить контрольную сумму в переменную, а затем в имя файла. Имя файла может содержать символы не ascii, но я не ожидаю увидеть переводы строки. Это выглядит так:

05c00367e8914ca1be0964821d127977 ./.fseventsd/0000000000097aa1 cd9d4291f59a43c0e3d73ff60a337bb5 ./.fseventsd/00000000000fdfec 5d1280769e741e04622cfd852f33a138 ./.fseventsd/0000000000103197 8dda3534e5bbc0be1d15db2809123c50 ./.fseventsd/000000000017c9ca (...etc., about 100,000 lines) 

Традиционно я мог бы выполнить что-то вроде этого:

 md5sum=$(echo $line | awk '{print $1}') filename=$(echo $line | sed 's/[^ ]* //') 

Но насколько быстрее это было бы, если бы я сделал это:

 md5sum=${line%%" "*} filename=${line#*" "} 

Да, использование внутренней команды bash позволяет избежать многих системных вызовов. Особенно, когда есть recursion.

Другой пример: мы должны использовать * против $ (ls).

Bash предлагает несколько способов сделать простые манипуляции со строками (срезы и подстановки). Но не более. Потому что это не для этого. Пример: трудно проверить наличие шаблона в строке без внешней команды.

Внешние программы более оптимизированы для своих задач (cat, sed, grep, awk, cut, sort, …)

Я проверил, установив одну из переменных. Выполняя этот скрипт дважды:

 while read line; do md5sum=${line%%" "*} #md5sum=$(echo $line | awk '{print $1}') echo "SUM: $md5sum FILE:_$file" done < manifest.Stuph.180620 

сначала с

 md5sum=${line%%" "*} 

и рядом с

 md5sum=$(echo $line | awk '{print $1}') 

где файл "manifest.Stuph.180620" длиной 100939 строк (== около 14 МБ) дал следующие результаты:

Первый запуск (с использованием встроенных в bash манипуляций со строками)

 real 0m4.750s user 0m4.174s sys 0m0.550s 

Второй прогон (по трубопроводу)

 real 10m54.255s user 4m42.257s sys 7m32.880s 

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

Обратите внимание, что делать это:

 while read md5sum filename; do (...etc...) 

даже более эффективно, чем выполнение присваивания переменных, но не до степени исключения конструкции подстановки команды / pipe / awk. Самое интересное, что я нахожу, это разница между встроенной производительностью bash и использованием внешних команд. Я буду более усердным в изучении и использовании модных встроенных вещей!