Возможно ли расширение параметров в тестовом выражении?

Возможно ли расширение параметров в тестовом выражении?

Когда я пробую следующее выражение, 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

Обратите внимание, что я использую [[...]]вместо [...]? Условие с двойными скобками более снисходительно к пустым значениям.

Связанный контент