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

Поскольку cpявляется командой пользовательского пространства, это не влияет на целостность файловой системы.

Вы, конечно, должны быть готовы к тому, что хотя бы один файл не будет скопирован полностью, если вы убьете работающую cpпрограмму.

0
02.06.2021, 19:10
2 ответа

Так и должно быть

some_func() {
  echo "$(( 3 + 5 ))"
}
[ "$(some_func)" -lt 10 ]

Почему это не удалось

$(some_func)расширяется до вывода функции*(за вычетом ее завершающей новой строки ), которая, однако, ничего не выводит. Следовательно, тест становится

[ -lt 10 ]

В своих самых основных формах тест [принимает от 1 до 3 параметров . Поскольку выше есть 2 параметра, Bash ожидает, что 1-й будет унарным оператором. -ltявляется двоичным, отсюда и сообщение об ошибке.

Если бы вы процитировали соответствующее расширение с

[ "$(some_func)" -lt 10 ]

Ошибка будет "ожидается целочисленное выражение", потому что тест будет иметь пустую строку:

[ "" -lt 10 ]

И, кроме нетривиальных -обстоятельств , && trueявляется излишним.

*Поскольку расширение не заключено в кавычки, вывод также подвергается разбиению на слова и расширению имени файла . Они не должны играть роли в данном примере, пока $IFSне было изменено по сравнению со значением по умолчанию.

6
28.07.2021, 11:27

$(cmd)получает стандартный вывод из cmd¹, поэтому для расширения до результата вам нужно от cmdдо вывести это:

some_func() {
  echo "$(( 3 + 5 ))"
}
[ "$(some_func)" -lt 10 ]

, как уже сказали другие. Однако это означает, что some_funcзапускается в среде подоболочки, поэтому любое изменение переменных или чего-либо еще будет впоследствии потеряно.

Например, нет смысла:

counter=0
incr() { echo "$((++counter))"; }
while [ "$(incr)" -le 10 ]...

, так как $(incr)всегда будет расширяться до 1 (, так как 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

Вы найдете более подробную информацию в этом ответе на другой вопрос и ответ о функции mksh valsub


¹ лишен завершающих символов новой строки, а в случае bash— символов NUL, а здесь, поскольку вы забыли кавычки, с учетом разделения + подстановки

4
28.07.2021, 11:27

Теги

Похожие вопросы