Я предлагаю вам проверить команду expect
. Аналогичная ситуация (с ssh
) должна выглядеть как ...
#!/usr/bin/expect
[...]
spawn ssh [lindex $argv 1]@root@[lindex $argv 0]@x.y.z.j -tt
expect "*?assword" {
send "$PASSWORD\r"
[...]
С помощью bash, используя утилиту readline, мы можем определить последовательность клавиш, чтобы поместить слово calc
в начало и заключить написанный текст в двойные кавычки:
bind '"\ec": "\C-acalc \"\e[F\""'
Выполнив это, вы набираете 23 + 46 * 89
, например, затем Alt-c , чтобы получить:
calc "23 + 46 * 89"
Просто нажмите Enter, и математические вычисления будут выполнены функцией, определенной как calc, которая может быть как простой, так и намного более сложной:
calc () { <<<"$*" bc -l; }
Мы можем определить псевдоним:
alias +='calc #'
Который прокомментирует всю набранную командную строку. Вы набираете:
+ (56 * 23 + 26) / 17
Когда вы нажмете ввод, строка будет преобразована в calc #(56 * 23 + 26) / 17
и будет вызвана команда calc
. Если calc это функция:
calc(){ s=$(HISTTIMEFORMAT='' history 1); # recover last command line.
s=${s#*[ ]}; # remove initial spaces.
s=${s#*[0-9]}; # remove history line number.
s=${s#*[ ]+}; # remove more spaces.
eval 'bc -l <<<"'"$s"'"'; # calculate the line.
}
calc(){ s=$(history -1 | # last command(s)
sed '$!d;s/^[ \t]*[0-9]*[ \t]*+ //'); # clean it up
# (assume one line commads)
eval 'bc -l <<<"'"$s"'"'; # Do the math.
}
zsh zsh не допускает ни псевдонима +
, ни символа #
.
Значение будет напечатано как:
$ + (56 * 23 + 26) / 17
77.29411764705882352941
Требуется только +
, строка заключена в кавычки (нет подстановок ), допустимы переменные оболочки:
$ a=23
$ + (56 * 23 + $a) / 17
77.11764705882352941176
С некоторыми ограничениями, это самое близкое, что я получил к вашему запросу с функцией (в bash):
+() { bc -l <<< "$*"; }
Что будет работать так:
$ + 25+68+8/24
93.33333333333333333333
Проблема в том, что синтаксический анализ оболочки нельзя избежать, и *
(, например ), может быть расширен до списка файлов в pwd.
Если вы напишете командную строку без (пробелов ), вероятно, все будет в порядке.
Остерегайтесь писать такие вещи, как $(...)
, потому что они будут расширены.
Безопасное решение — заключать оцениваемую строку в кавычки.:
$ + '45 + (58+3 * l(23))/7'
54.62949752111249272462
$ + '4 * a(1) * 2'
6.28318530717958647688
Что всего на на два символа короче вашего _bc "6/2"
, но +
кажется мне более интуитивным.
В zsh
вы можете сделать что-то вроде:
autoload zcalc
accept-line() {
if [[ $BUFFER =~ '^[ (]*[+-]? *(0[xX]|.)?[[:digit:]]+[^[:alnum:]]' ]]; then
echo
zcalc -e $BUFFER
print -rs -- $BUFFER
BUFFER=
fi
zle.$WIDGET
}
zle -N accept-line
Он переопределяет виджет accept-line
(, сопоставленный с Введите)в пользовательский -виджет, который проверяет, начинается ли текущая строка с числа (десятичного или шестнадцатеричного )опционально с префиксом любого количества (
s, ища после этого не -alnum символ, чтобы избежать ложных срабатываний для таких команд, как 7zip
или 411toppm
.
Если это совпадает, мы передаем его вzcalc
(более полезное, чем bc, поскольку оно может использовать переменные оболочки и все математические функции zsh и числовые стили, но не поддерживает произвольную точность ), добавьте строку в историю и принять пустую команду.
Учтите, что это может привести к путанице, если вы введете строку с цифрами в таких вещах, как:
cat << EOF
213 whatever
EOF
Или:
var=(
123 456
)
Вдохновлен ответом Стефана zsh и длиннее, чем ответ Исаака bash в целом, но короче в работе:
trap '[[ $_ =~ [[:digit:]] ]] && bc -l <<< "$_"' ERR
Это также имеет побочный эффект: каждый раз отображается ошибка «Нет такого файла или каталога»:
$ foozle
-bash: foozle: command not found
$ 1+2+3
-bash: 1+2+3: command not found
6
$ 6/3
-bash: 6/3: No such file or directory
2.00000000000000000000
Регулярное выражение может быть ужесточено в зависимости от ожидаемых операций.
Этот (ab )использует поведение bash для вызова ловушки ERR, когда данная команда не существует. Если последняя команда (в$_
)содержит цифру, то выполняется bc
для этой «команды».
Благодаря подсказке Стефана , вот более чистый способ достижения результата (требуется bash 4.0 или более поздняя версия, в которой появилась функциональность):
if ! declare -F command_not_found_handle > /dev/null
then
command_not_found_handle() {
if [[ "$@" =~ [[:digit:]] ]]; then
bc <<< "$@";
else
printf 'bash: %s: command not found\n' "$1" >&2
return 127
fi
}
else
echo Unable to set up the handler function, sorry
fi
Функция вызывается всякий раз, когда команда не найдена. Если эта команда содержит цифру, мы бросаем ее через bc
; в противном случае мы выдаем сообщение, подобное стандартному сообщению bash, и возвращаем код выхода 127.
Другим несовершенным способом сделать это в Bash было бы использование ловушки DEBUG
, которая срабатывает при каждой команде. С установленным extdebug
обработчик trap может предотвратить запуск основной команды, поэтому вы не получите ошибки «команда не найдена».
$ cat bash_calc.sh
shopt -s extdebug
debug_calc() {
local re='^[ (]*-?[0-9]'
if [[ $BASH_COMMAND =~ $re ]]; then
echo "$BASH_COMMAND" | bc -l
return 1
fi
}
trap debug_calc DEBUG
$../bash_calc.sh
$ 123 * 456
56088
$ 123/456
.26973684210526315789
Ловушка получает полную командную строку перед расширением переменных или шаблонов имен файлов, поэтому *
без кавычек работает. (Но использование переменных оболочки в вычислениях не работает.)
Однако скобки без кавычек по-прежнему вызывают синтаксическую ошибку, так что это тоже не идеально.
(Я взял регулярное выражение выше из ответа Стефана .)
Я использую вариант хака magic alias от bash:
asis() { bc <<< "$(history 1 | perl -pe 's/^ *[0-9]+ +[^ ]+ //')"; }
alias c='asis #'
Тогда:
$ c 1+1
2
$ c -10 + 20 / 5
-6
$ c (-10 + 20) / 5
2
$ c 2^8 / 13
19
$ c scale=5; 2^8 / 13
19.69230
Волшебство заключается в том, что расширение псевдонима происходит до обычной обработки командной строки, что позволяет нам создать команду, оставшиеся аргументы которой следуют за символом комментария, который реализующая функция находит с помощью команды history.
Эта магия позволяет мне вводить *
, (
и другие символы буквально.Но это также означает, что я не могу использовать переменные оболочки, потому что $
также литерал:
$ x=5.0
$ y=-1.2
$ z=4.7
$ c ($x + $y) > $z
(standard_in) 1: illegal character: $
(standard_in) 1: illegal character: $
(standard_in) 1: illegal character: $
Я обхожу это с помощью начальной загрузки:
$ echo "x=$x; y=$y; z=$z"
x=5.0; y=-1.2; z=4.7
$ c x=5.0; y=-1.2; z=4.7; (x + y) > z
0
Лучше наберите:bc
Enter 1 + 1 EnterControl+D
В качестве примечания: у меня есть настройки по умолчанию bc
(, такие какscale
)в $HOME/.bc
, и я использую bc -l
в псевдониме. Для вашего использования эти модификации могут не потребоваться.
Следующие командные строки довольно просты для ввода,
<<< 5+4 bc
<<< 6/3 bc
<<< 7*2 bc
и несколько сложнее со скобками (должны быть заключены в кавычки или экранированы ),
<<< "(5+4)*2/3" bc
<<< \(5+4\)*2/3 bc