Вы можете установить ограничения перед запуском процесса. Например, установите ограничение виртуальной (мягкой) памяти для текущей оболочки на 1 ГБ
ulimit -S 1048576
. Вы также можете установить такие ограничения для всей системы, например, у меня есть это:
/etc/security/limits.conf:
* soft as 25165824
* hard as 25165824
/etc/systemd/system.conf:
DefaultLimitAS = 25769803776
Чтобы ограничить все процессы 24G на мои системы 32G. Хотя два процесса вместе могли вызвать такую ситуацию OOM, на практике этого никогда не происходило.
Относительно «долгое время не отвечал, прежде чем убить наступательный процесс»:
Обратите внимание: на самом деле проблема не в malloc (виртуальной памяти). OOM происходит только тогда, когда процесс начинает использовать эту распределенную память. К сожалению, в Linux вы не можете ограничить резидентную память. См. «Перегрузка памяти»:
Если вы используете bash
, вы можете сделать что-то вроде этого (с дополнительными echo
операторами, чтобы показать, что происходит на каждом этапе):
$ line=dog,/path1,/path2
$ newline=$(printf "%s\n" "$line" |
perl -n -e 'BEGIN {$count=1};
my ($var,@values) = split /,/;
print "$var=" . join(",",@values);
foreach (@values) {
printf "%s%i=\"%s\" ",$var, $count++, $_
}')
$ echo "$newline"
dog=/path1,/path2 dog1=/path1 dog2=/path2
$ declare $newline
$ declare | grep '^dog'
dog=/path1,/path2
dog1=/path1
dog2=/path2
Это использует perl
для разделения $line
запятыми. Первое поле сохраняется в $var
, остальные - в массиве @values
. Затем он производит вывод, пригодный для использования с командой bash declare
для установки переменных.
Обратите внимание, что $newline
в строке declare
не заключается и не должен заключаться в двойные кавычки. Если она будет заключена в двойные кавычки, declare
получит только один аргумент, а не три, разделенные пробелами.
Одним из неприятных побочных эффектов отсутствия кавычек здесь является то, что declare
WILL не работает, если любое из значений поля содержит пробелы и т.д. Например, line=dog,/path /with / spaces,/path2
. При необходимости это можно исправить, выводя соответствующие цитаты из операторов print
и printf
в скрипте perl
. И/или определив $newline
как массив bash вместо строки. Оставим это упражнение для читателя, так как я уже достаточно показал принцип/технику, используемую здесь.
Если вы хотите объявить их как экспортируемые переменные, используйте:
declare -x $newline
подробнее см. в help declare
.
BTW, в ksh
вы можете использовать typeset
вместо declare
. typeset
также поддерживается bash
, но считается устаревшим (см. help typeset
в bash
).
И наконец: вы уверены, что не предпочли бы использовать переменную массива shell (например, dog[0]=/path1,/path2
, dog[1]=/path1
, и dog[2]=/path2
), а не отдельные переменные?
Именно для таких вещей они и существуют.
Вы можете сделать что-то вроде этого. Я определяю линию как у вас. Затем я анализирую наш первый токен, разделенный запятыми, из строки (я предполагаю, что здесь он будет действителен для имени переменной). Затем я создаю две новые переменные на основе первого токена и назначаю их второму и третьему разделенным запятыми токенам из строки.
line="dog,/path1,/path2"
first="$(echo "${line}" | awk -F, '{ print $1 }')"
eval "${first}1=$(echo "${line}" | awk -F, '{ print $2 }')"
eval "${first}2=$(echo "${line}" | awk -F, '{ print $3 }')"
echo "${dog1}"
/path1
echo "${dog2}"
/path2
Вот решение, ориентированное на bash:
IFS=, read -r -a vars <<<"$line"
printf "%s\n" "${vars[0]}=${vars[1]},${vars[2]}" "${vars[0]}1=${vars[1]}" "${vars[0]}2=${vars[2]}"
Первая строка разделяет вашу переменную $ line
на части на основе запятых. Вторая строка, работающая наизнанку:
1
, знак равенства, затем второе значение, 2
, знак равенства, затем третье значение, printf
эти три строки, разделенные переводом строки. Этот ответ, как и ваш вопрос, жестко запрограммирован на наличие трех значений в $ line
.
Пример ввода и вывода (первые $
- это приглашения оболочки):
$ line=dog,/path1,/path2
$ IFS=, read -r -a vars <<<"$line"
$ printf "%s\n" "${vars[0]}=${vars[1]},${vars[2]}" "${vars[0]}1=${vars[1]}" "${vars[0]}2=${vars[2]}"
dog=/path1,/path2
dog1=/path1
dog2=/path2
Вы можете достаточно легко перенаправить вывод printf в файл.
Я думаю, что это то, что вы пытаетесь сделать:
line='dog,/path1,/path2'
IFS=', ' read -r -a dog <<< "$line"
echo "$dog"
dog
echo "${dog[1]}"
/path1
echo "${dog[2]}"
/path2
Предполагается, что ваша оболочка - bash.