Когда я пробую следующее выражение, bash
я получаю странное сообщение об ошибке:
[: -lt: unary operator expected
Сначала определение функции
some_func () {
(( 3 + 5 ))
}
И выражение
[ $(some_func) -lt 10 ] && true
Полагаю, проблема в смешивании операторов, таких как -lt
подстановка команд и/или арифметическое расширение?
Код выхода $?
— 2, а сообщение —an unary op was expected
.
решение1
Должен быть
some_func() {
echo "$(( 3 + 5 ))"
}
[ "$(some_func)" -lt 10 ]
Почему это не удалось
$(some_func)
расширяется довыходфункции* (за исключением завершающего символа новой строки), которая, однако, ничего не выводит. Поэтому тест становится
[ -lt 10 ]
В своих самых основных формах,тест [
принимает от 1 до 3 параметров. Поскольку выше указано 2 параметра, Bash ожидает, что первый из них будет унарным оператором. -lt
является бинарным, отсюда и сообщение об ошибке.
У тебя былпроцитировал расширение как уместноес
[ "$(some_func)" -lt 10 ]
Ошибка будет выглядеть так: «Ожидается целочисленное выражение», поскольку тест будет содержать пустую строку:
[ "" -lt 10 ]
И, если только поднетривиальные обстоятельства, && true
является избыточным.
*Поскольку расширение не заключено в кавычки, вывод также подвергаетсяразделение словирасширение имени файла. Они не должны играть никакой роли в данном примере, если только $IFS
их значение по умолчанию не было изменено.
решение2
$(cmd)
получаетстандартный выводиз cmd
¹, поэтому для того, чтобы расширить его до результата, вам cmd
нужновыходэто:
some_func() {
echo "$(( 3 + 5 ))"
}
[ "$(some_func)" -lt 10 ]
как уже сказали другие. Однако это означает, что some_func
он запускается в среде подоболочки, поэтому любые изменения переменных или чего-либо еще будут впоследствии утеряны.
Например, нет смысла делать:
counter=0
incr() { echo "$((++counter))"; }
while [ "$(incr)" -le 10 ]...
as $(incr)
всегда будет расширяться до 1 (as counter
будет увеличиваться только в подоболочке).
Для функции, возвращающей числовой результат черезарифметическая оценка, вам понадобится оболочка с поддержкойматематические функциинравится ksh93
или zsh
. bash
не подойдет.
В zsh
:
counter=0
incr() (( ++counter ))
functions -M incr
while (( incr() <= 10 )); do
print $counter
done
В ksh93
:
function .sh.math.incr i {
# ksh93 functions must take at least one argument
(( .sh.value = (counter += i) ))
}
while (( incr(1) <= 10 )); do
print "$counter"
done
Другой альтернативой в ksh93 или последних версиях mksh является использование форм подстановки команд, которые не вводят подоболочки:
counter=0
function incr { print "$(( ++counter ))"; }
while [ "${ incr; }" -le 10 ]; do
print "$counter"
done
Или в mksh
:
counter=0
incr() (( REPLY = ++counter ))
while [ "${| incr; }" -le 10 ]; do
print "$counter"
done
В любой оболочке POSIX, включая bash
, вы всегда можете вернуть значение в предопределенной переменной ( $REPLY
обычно для этого используется ):
counter=0
incr() { REPLY=$(( counter += 1 )); }
while incr; [ "$REPLY" -le 10 ]; do
echo "$counter"
done
Более подробную информацию вы найдете на сайтеэто ответ на другой вопрос и ответ о функции valsub в mksh
¹ удалены конечные символы новой строки, а в случае с bash
— символы NUL, а здесь, поскольку вы забыли кавычки, подлежат split+glob
решение3
Замена командыфиксирует выводкоманды или функции. Эта функция не имеет выходных данных.
Переменная $?
содержиткод возвратафункции.
Либо сделайте это:
some_func
(( $? < 10 )) && echo yes
или измените функцию на:
some_func() {
echo $(( 3 + 5 ))
}
[[ $(some_func) -lt 10 ]] && echo yes
Обратите внимание, что я использую [[...]]
вместо [...]
? Условие с двойными скобками более снисходительно к пустым значениям.