1

Я написал следующий код: примерКак `((...))` отличается от `(...)`?

case "$2" in '+') ((res = $1 + $2));; 

       '-') ((res = $1 - $2));; 
esac 

echo $res 

Использование: ./"*filename*" 2 + 3

Если я использую двойные круглые скобки,

((res = $1 + $2)) 

то результат печатается. Однако, если я использую одиночные круглые скобки

(res = $1 + $2) 

тогда ничего не печатается. В чем разница между () и (())?

+0

Какая оболочка вы с помощью? – melpomene

+0

'((...))' для [арифметического расширения] (http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_04), тогда как '(...)' запускает вложенную команду в подоболочку, которая не влияет на ее родительскую оболочку. – Jubobs

+0

Также обратите внимание, что в вашем примере вторым параметром ('$ 2') является оператор, а не второй операнд. Соответственно, вы, вероятно, хотите '((res = $ 1 + $ 3))' и '((res = $ 1 - $ 3)), здесь. – Jubobs

ответ

2

Двойные скобки ((...)) предназначены для arithmetic expansion, в то время как одиночные скобки (...) запустить прилагаемую команду в subshell, которая имеет свою собственную сферу и не влияет на окружающую среду своей родительской оболочки.

Здесь с (res = $1 + $2), даже если переменная res успешно присвоено значение в субоболочке, res остается неустановленным в родительской оболочке, что объясняет, почему ничего не печатается. Вы хотите использовать ((...)), в данном конкретном случае.

Кроме того, обратите внимание, что в вашем примере второй параметр, $2, является оператором, а не вторым операндом. Соответственно, вам нужно вместо этого использовать ((res = $1 + $3)) и ((res = $1 - $3)).

Кроме того, для надежности, вы можете убедиться, что

  • количество аргументов, действительно,
  • первые и третьи аргументами являются допустимыми целыми числами,
  • второго параметра является допустимым арифметический оператор (+ или -, здесь),
  • т.д.

Наконец, для улучшения переносимости в разных оболочках предпочтительнее printf по сравнению с echo.

уточнена и доработана код

#!/bin/sh 

# foo 

# Custom error function 
die() { 
    printf "%s\n" "$1" 1>&2 ; 
    exit 1; 
} 

# Function that returns an exit status of 
# 0 if its first argument is a valid integer, 
# 1 otherwise. 
is_integer() { 
    [ "$1" -eq 0 -o "$1" -ne 0 ] >/dev/null 2>&1 
} 

# Check that the number of argument is 3 
[ "$#" -eq 3 ] || die "invalid number of arguments" 

# Check that the operands are valid integers 
is_integer "$1" || die "invalid first operand" 
is_integer "$3" || die "invalid second operand" 

# If the second argument is a valid operator, assign res accordingly; 
# otherwise, die. 
case "$2" in 
    '+') 
    ((res = $1 + $3)) 
    ;; 
    '-') 
    ((res = $1 - $3)) 
    ;; 
    *) 
    die "invalid operator" 
    ;; 
esac 

printf "%s\n" "$res" 

Тесты

После создания сценария (так называемый "Foo") исполняемый файл, запустив

chmod u+x foo 

Я получаю следующие результаты

$ ./foo -18 + 5 
-13 
$ ./foo 9 - 4 
5 
$ ./foo a + 2 
invalid first operand 
$ ./foo -18 + c 
invalid second operand 
$ ./foo 3/4 
invalid operator 
+2

Аплодисменты для использования printf вместо echo. – Jens