Как отключить специальные символы в bash?
Я создал скрипт, который выполняет расчет. Например:count 1 + 3
1 + 3 = 4
,-
а также /
тоже работает, но если я наберу count 1 * 3
, Я получил
Должен быть номер операнда номер
Вот часть сценария:
if [ "$#" -ne 3 ]; then
echo "Should be number operand number"
exit 1
fi
...
elif [ "$2" = "*" ]; then
result=`echo $1 \* $3 | bc`
echo "$1 * $3 = $result"
Да, если я наберу \
до *
в командной строке это будет работать, но мне нужно, чтобы он работал только с *
,
Я пытался использовать набор -f
внутри скрипта он не работал (да, он отключает специальные символы, если я набираю сам bash, но это не то, что мне нужно). Также есть shopt
команда, которая контролирует поведение оболочки, поэтому я попытался включить некоторые параметры, такие как shopt -s globstar
, nullglob
, promptvars
и т.д. Это не сработало. Я поставил команду перед оператором if, может быть, это неправильно.
Я был бы признателен, если бы кто-то исправил меня или сказал другой способ отключить интерпретацию специального символа внутри скрипта.
2 ответа
Эта точная проблема упоминается в спецификации POSIX выражения expr, где говорится, что инструмент имеет "довольно сложный синтаксис" по той причине, которую вы описываете.
Другими словами, это определенно известная проблема, и сам POSIX оставляет ее нерешенной. Вы действительно должны подумать о работе с Unix и делать то же самое, а не пытаться работать против него.
Некоторые варианты:
Требовать полного выражения для одного аргумента в кавычках, например
count "1 * 2"
Это прагматичный, безотказный способ гарантировать, что аргумент всегда заключается в кавычки, так что любое введение * все еще работает. Встроенный bash
let
Является ли это.read
выражение себя, например, просто запуститьcount
а затем введите1 * 2
,Это позволяет избежать того, что оболочка касается ваших данных, поэтому вы можете интерпретировать их так, как хотите. Это что
bc
а такжеdc
делать.Жить с тем, что мимоходом
*
потребует тщательного цитирования.Это то, что
expr
делает.Используйте магический псевдоним, который работает только на определенных оболочках при определенных обстоятельствах.
Это то, что никто не делает, потому что оно хрупкое и непредсказуемое, хотя в некоторых случаях позволяет использовать нужный синтаксис.
Всегда цитируйте, когда вы эхо. Вам также нужно заключить в кавычки переменную:
me$ FOO="BAR * BAR"
me$ echo "$FOO"
BAR * BAR
Если вы не используете двойные кавычки, bash увидит *
и выполнить расширение имени файла. *
расширяется на все файлы в вашем текущем каталоге.
Однако, говоря это, вы должны использовать одинарные кавычки для *
:
#!/bin/bash
if [ "$2" = "*" ]; then
result=`echo $1 \* $3 | bc`
echo "$1 * $3 = $result"
fi
Следующее будет работать:
» count.sh 2 '*' 1
2 * 2 = 4
Вы ничего не можете сделать в своей программе, потому что *
расширение выполняется оболочкой (в отличие от Windows, где это делается программой).
Вот еще один пример кода, использующий подход, основанный на меню:
#!/bin/bash
while true; do
read -p "what's the first number? " n1
read -p "what's the second number? " n2
PS3="what's the operation? "
select ans in add subtract multiply divide; do
case $ans in
add) op='+' ; break ;;
subtract) op='-' ; break ;;
multiply) op='*' ; break ;;
divide) op='/' ; break ;;
*) echo "invalid response" ;;
esac
done
ans=$(echo "$n1 $op $n2" | bc -l)
printf "%s %s %s = %s\n\n" "$n1" "$op" "$n2" "$ans"
done
what's the first number? 5
what's the second number? 4
1) add
2) subtract
3) multiply
4) divide
what's the operation? /
invalid response
what's the operation? 4
5 / 4 = 1.25000000000000000000
Вкратце, процитируйте все, где вам не требуется оболочка для разделения токенов и подстановочных знаков.