Здесь речь идет не об открытии файла, а о прочтении содержимого переменной, а скорее о том, чтобы создать дополнительный процесс или нет.
grep -oP '^MemFree: *\K[0-9]+' /proc/meminfo
разветвляется процесс, который запускается, grep
который открывается /proc/meminfo
(виртуальный файл, в памяти, без дискового ввода-вывода) читает его и соответствует регулярному выражению.
Самая дорогая часть в этом - это разветвление процесса и загрузка утилиты grep и ее зависимостей от библиотеки, динамическое связывание, открытие базы данных локали, десятки файлов, которые находятся на диске (но, вероятно, кешируются в памяти).
Часть о чтении /proc/meminfo
несущественна по сравнению с тем, что ядру не нужно много времени, чтобы генерировать информацию, и не grep
нужно много времени, чтобы ее прочитать.
Если вы выполните strace -c
это, вы увидите, что один open()
и один read()
системные вызовы, используемые для чтения, /proc/meminfo
- это арахис по сравнению со всем, что grep
нужно для запуска ( strace -c
не считая разветвления).
В:
a=$(</proc/meminfo)
В большинстве оболочек, которые поддерживают этот $(<...)
оператор ksh, оболочка просто открывает файл и читает его содержимое (и удаляет завершающие символы новой строки). bash
отличается и намного менее эффективен в том, что он разветвляет процесс, выполняющий это чтение, и передает данные в родительский канал по каналу. Но здесь это делается один раз, поэтому это не имеет значения.
В:
printf '%s\n' "$a" | grep '^MemFree'
Оболочка должна порождать два процесса, которые работают одновременно, но взаимодействуют друг с другом через канал. Создание этой трубы, ее разрушение, а также запись и чтение из нее имеют небольшую стоимость. Гораздо большая стоимость порождает дополнительный процесс. Планирование процессов также оказывает определенное влияние.
Вы можете обнаружить, что использование <<<
оператора zsh делает его немного быстрее:
grep '^MemFree' <<< "$a"
В zsh и bash это делается путем записи содержимого $a
во временный файл, что обходится дешевле, чем запуск дополнительного процесса, но, вероятно, не даст вам никакой выгоды по сравнению с получением данных сразу /proc/meminfo
. Это все еще менее эффективно, чем ваш подход, который копирует /proc/meminfo
на диск, так как запись временного файла выполняется на каждой итерации.
dash
не поддерживает здесь-строки, но его heredocs реализованы с помощью канала, который не требует создания дополнительного процесса. В:
grep '^MemFree' << EOF
$a
EOF
Оболочка создает трубу, разветвляет процесс. Дочерний элемент выполняется grep
со своим стандартным вводом-выводом в качестве конца чтения канала, а родительский элемент записывает содержимое на другом конце канала.
Но такая обработка каналов и синхронизация процессов все еще могут быть более дорогостоящими, чем просто получение данных /proc/meminfo
.
Содержание /proc/meminfo
короткое и не занимает много времени для производства. Если вы хотите сохранить некоторые циклы ЦП, вы хотите удалить дорогостоящие детали: разветвление процессов и запуск внешних команд.
Подобно:
IFS= read -rd '' meminfo < /proc/meminfo
memfree=${meminfo#*MemFree:}
memfree=${memfree%%$'\n'*}
memfree=${memfree#"${memfree%%[! ]*}"}
Избегайте, bash
чье сопоставление с образцом очень неэффективно. С помощью zsh -o extendedglob
вы можете сократить его до:
memfree=${${"$(</proc/meminfo)"##*MemFree: #}%%$'\n'*}
Обратите внимание, что ^
это особенность во многих оболочках (Bourne, fish, rc, es и zsh, по крайней мере, с параметром extendedglob), я бы рекомендовал процитировать его. Также обратите внимание, что echo
не может использоваться для вывода произвольных данных (отсюда мое использование printf
выше).