У меня проблема с sh
синтаксисом скрипта. Я написал скрипт для своего роутера Asus. Скрипт работает отлично. Но у меня есть эта строка:
if [[ "$OldIP" && "$StartIP" != "$OldIP" ]]; then echo OK; fi
Он должен быть истинным ( и выполняться echo OK
) только если $StartIP
и $OldIP
не являются одинаковыми. Строка работает, но я хотел бы видеть ее более эффективной. Переменные содержат допустимые IP-адреса.
В некоторых случаях $OldIP
ничего не будет назначено (не инициализировано). Но если $OldIP
не существует, значит, в моей оболочке они не одинаковы!
Я не хочу, чтобы строка делала: если $OldIP
не существует -> проверить, различны ли они -> запустить echo OK
.
Я хочу, чтобы строка означала: а) если $OldIP
не существует -> конец. плюс б) если $OldIP
существует -> проверить, различны ли они -> запустить echo OK
.
Так что я хотел бы как-то удалить "$OLDIP" &&
, если это возможно. Не настоящая проблема; интересно узнать :)
Что-то вроде того (но это не работает):
if [ [ "$OldIP" ] != "$StartIP" ]; then echo OK; fi
или
if [ $OldIP != "$StartIP" ]; then echo OK; fi
который делает то, что я хочу, но жалуется, когдаСтарый IPпусто (но работает нормально)
пока
if [ "$OldIP" != "$StartIP" ]; then echo OK; fi
работает, но игнорирует этоСтарый IPпусто
решение1
Строго говоря, переменная не существует, если ей никогда не было присвоено значение или если ей было присвоено unset
. Переменная с пустой строкой в качестве значениясуществует.
Стандартное расширение параметра ${variable+value}
заменит строку, value
если variable
существует (не является неустановленным или пустым). Это можно использовать для проверки существования следующим образом:
if [ "${OldIP+x}" = "x" ] && [ "$OldIP" != "$StartIP" ]; then
# code
fi
Чтобы проверить, OldIP
существует ли в bash
, используйте -v
тест:
if [[ -v OldIP ]] && [[ "$OldIP" != "$StartIP" ]]; then
# code
fi
Это выполнит сравнение строк между $OldIP
и $StartIP
только если OldIP
было установлено ранее (даже если оно было установлено на пустую строку). Обратите внимание, что тест -v
принимаетимяпеременной.
решение2
Я думаю, что ваш скрипт и так довольно эффективен. Вы определенно не тратите много циклов на это.
Другой способ записать логику:
{ test -n "$OldIP" || test "$StartIP" != "$OldIP"; } && echo OK
Здесь говорится: «Если установлен OldIP или OldIP и StartIP различны, то вывести OK».
Помните, что это [
еще одно название, о test(1)
котором вы можете прочитать здесь man 1 test
.
Редактировать: Как указал Жиль, старайтесь избегать создания подоболочек ( ... )
там, где они не нужны.
{ ... ; }
может использоваться для группировки команд без запуска новой оболочки.
Краткая справка:http://www.gnu.org/software/bash/manual/html_node/Command-Grouping.html
решение3
Это делает то, о чем вы просите:
[ "${OldIP:-"$StartIP"}" != "$StartIP" ] && echo "OK"
А также это (более сложное):
${OldIP:+false} || { [[ $OldIP != $StartIP ]] && echo "OK"; }
решение4
Если вы используете bash
, вы можете использовать замену по умолчанию:
[[ "${OldIP:=oldunset}" != "${StartIP?StartUnset" ]] && echo "OK"
Синтаксис ${var:-def}
будет оцениваться либо текущим значением $var
, либо указанным значением по умолчанию (в данном случае def
), если переменная не установлена или равна нулю. Значение переменной (если есть) не изменяется.
Синтаксис ${var?message}
завершится с кодом ошибки 1 и сообщением, message
если $var
он не установлен или равен нулю.
Если вам явно нужны test
-совместимые тесты, вы можете сделать это:
[ ! -z "$OldIP" -a "$OldIP" != "$StartIP" ] && echo "OK"