Да, я нашел решение, использующее сочетание массивов и sed ..:
#delete the old values
sed -i 's/speed:\(.\), //g' "$FILENAME"
sed -i 's/speed:\(..\), //g' "$FILENAME"
sed -i 's/speed:\(...\), //g' "$FILENAME"
sed -i 's/speed:\(....\), //g' "$FILENAME"
#create an array with just the urls
SERVER=( $(sed -nre 's/.*server:"(.*)".*/\1/p' "$FILENAME") )
#for each element
for element in $(seq 0 $((${#SERVER[@]}-1)))
do
#calculate the new average ping speed
SPEED[element]="$( sudo ping -c2 "${SERVER[element]}" | grep rtt | cut -f 5 -d '/' )"
#if server is not available
if [ -z "${SPEED[element]}" ]; then SPEED[element]=1000 ; fi
#add the old server speed
sed -i "s/\"\(${SERVER[element]}\)\"/\"\1\", speed:${SPEED[element]}/g" "$FILENAME"
done
Может быть, не работает, но работает и может быть полезно
Это сводится к вопросу о том, как работает оценка. Оба примера работают одинаково, проблема возникает из-за того, как оболочка (здесь bash) расширяет переменные.
Когда вы пишете эту команду:
HOME="foo" echo $HOME
$ HOME
раскрывается перед запуском команды . Следовательно, оно расширяется до исходного значения, а не до нового значения, которое вы установили для команды. Переменная HOME
действительно была изменена в среде, в которой выполняется команда echo
, однако вы печатаете $ HOME
из родительского объекта.
Для иллюстрации рассмотрим следующее:
$ HOME="foo" bash -c 'echo $HOME'
foo
$ echo $HOME
/home/terdon
Как вы можете видеть выше, первая команда печатает временно измененное значение HOME
, а вторая печатает оригинал, демонстрируя, что переменная была изменена только временно. Поскольку bash -c ...
команда заключена в одинарные кавычки ( ''
) вместо двойных ( «»
), переменная не раскрывается и передается как есть в новый процесс bash. . Затем этот новый процесс расширяет его и печатает новое значение, на которое он был установлен. В этом можно убедиться, если использовать set -x
:
$ set -x
$ HOME="hello" echo "$HOME"
+ HOME=hello
+ echo hello
hello
Как видно выше, переменная $ HOME
никогда не передается в echo
]. Он видит только его расширенную ценность. Сравните с:
$ HOME="hello" bash -c 'echo $HOME'
+ HOME=hello
+ bash -c 'echo $HOME'
hello
Здесь из-за одинарных кавычек переменная, а не ее значение, передаются новому процессу.
Существует две области действия: переменные среды и локальные переменные.
Переменные среды действительны для каждого процесса (см. setenv
, getenv
), а локальные переменные - активен только в рамках этого сеанса оболочки. (Это не очевидное различие ...)
Подразумеваемое env
(как в вашем примере) изменяет среду, а echo ...
использует локальные, поэтому ] env
не действует.
Чтобы изменить локальные переменные, используйте, скажем,
( HOME="foo" ; echo "$HOME" )
Здесь круглые скобки определяют объем этого присваивания.
Когда оболочка анализирует строку, она разбивает строку на слова, выполняет различные расширения (по порядку) для слов , затем выполните команду.
Предположим, test = 1: 2: 3: 4: 5: 6
Давайте посмотрим на эту команду: IFS = ":" read abcdef <<< "$ test"
После происходит разметка и расширение параметра : IFS = ":"
читать
a
b
c
d
e
f
<<<
"1: 2: 3: 4: 5: 6"
Оболочка установит переменную IFS на время выполнения команды чтения, а read
знает, как примените $ IFS к его входу и присвойте значения именам переменных.
Эта команда имеет аналогичную историю, но другой результат: HOME = "hello" echo "$ HOME"
Поскольку расширение параметра происходит до начала команды, оболочка имеет:
HOME="hello" echo "/home/username"
И затем, во время выполнения команды echo, новое значение $ HOME вообще не используется.
Чтобы достичь того, что вы пытаетесь сделать, выберите одно из
# Delay expansion of the variable until its new value is set
HOME="hello" eval 'echo "$HOME"'
или
# Using a subshell, so the altered env variable does not affect the parent.
# The semicolon means that the variable assignment will occur before
# the variable expansion
(HOME="hello"; echo "$HOME")
, но не выбирайте первый.