Я нашел эти примеры на SO в этих вопросах и ответах под названием: Как выполнить цикл for для каждого символа в строке в BASH? .
Вот сценарий под названием onechar1.bash
.
#!/bin/bash
echo "Please enter a word:
(leave blank and press Enter to exit)"
read someStr
if [[ $someStr == '' ]]; then
exit
fi
while test -n "$someStr"; do
c=${someStr:0:1} # Get the first character
echo "character is $c"
someStr=${someStr:1} # trim the first character
done
Когда я запускаю его:
$ ./onechar1.bash
Please enter a word:
(leave blank and press Enter to exit)
My Name is Mauro
character is M
character is y
character is
character is N
character is a
character is m
character is e
character is
character is i
character is s
character is
character is M
character is a
character is u
character is r
character is o
$
Вот еще один сценарий, onechar2.bash
:
#!/bin/bash
echo "Please enter a word:
(leave blank and press Enter to exit)"
read someStr
if [[ $someStr == '' ]]; then
exit
fi
for (( i=0; i<${#someStr}; i++ )); do
echo ${someStr:$i:1}
done
Когда я запускаю этот сценарий:
$ ./onechar2.bash
Please enter a word:
(leave blank and press Enter to exit)
My Name is Mauro
M
y
N
a
m
e
i
s
M
a
u
r
o
$
Здесь речь идет не об открытии файла и чтении содержимого переменной , а о разветвлении дополнительного процесса или нет.
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
выше ).
Вы вызываете внешнюю команду в обоих случаях (grep ). Для внешнего вызова требуется подоболочка. Разветвление этой оболочки является основной причиной задержки. Оба случая похожи, поэтому :одинаковая задержка.
Если вы хотите прочитать внешний файл только один раз и использовать его (из переменной )несколько раз, не выходите из оболочки:
meminfo=$(< /dev/meminfo)
time for i in {1..1000};do
[[ $meminfo =~ MemFree:\ *([0-9]*)\ *.B ]]
printf '%s\n' "${BASH_REMATCH[1]}"
done
Это занимает всего около 0,1 секунды вместо полной 1 секунды для вызова grep.
В вашем первом случае вы просто используете утилиту grep и находите что-то в файле /proc/meminfo
, /proc
— это виртуальная файловая система, поэтому файл /proc/meminfo
находится в памяти, и для извлечения его содержимого требуется очень мало времени..
Но во втором случае вы создаете канал, а затем передаете вывод первой команды второй команде, используя этот канал, что дорого.
Разница в том, что/proc
(находится в памяти )и канале, см. пример ниже:
time for i in {1..1000};do grep ^MemFree /proc/meminfo;done >/dev/null
real 0m0.914s
user 0m0.032s
sys 0m0.148s
cat /proc/meminfo > file
time for i in {1..1000};do grep ^MemFree file;done >/dev/null
real 0m0.938s
user 0m0.032s
sys 0m0.152s
time for i in {1..1000};do echo "$a"|grep ^MemFree; done >/dev/null
real 0m1.016s
user 0m0.040s
sys 0m0.232s