快捷方式Alt- c(bash)

快捷方式Alt- c(bash)

有时我需要运行一些数学运算。我知道我可以使用bcor echo $(( 6/2 ))。我创建了自己的函数来bc读取输入。但有时需要很长时间才能输入:_bc "6/2"。所以我有这个问题:

有没有办法教 zsh/bash 如何在命令行中对数字运行数学运算?举一例,胜过千言万语。

$ 6/2
$ 3.0

意思是zsh/bash必须识别数字并调用ie公元前

答案1

快捷方式Alt- c(bash)

在 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

当您按 Enter 键时,该行将被转换并调用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 不允许使用+别名或#字符。

该值将打印为:

 $ + (56 * 23 + 26) / 17
 77.29411764705882352941

+需要 a,引用 String(无通配符),接受 shell 变量:

 $ a=23
 $ + (56 * 23 + $a) / 17
 77.11764705882352941176

(+) 函数

由于存在一些限制,这是我使用函数(在 bash 中)最接近您的请求的:

+() { bc -l <<< "$*"; }

它将像这样工作:

$ + 25+68+8/24
93.33333333333333333333

问题是无法避免 shell 解析,并且 a *(例如)可能会扩展到 pwd 中的文件列表。

如果您编写的命令行没有(空白)空格,您可能会没问题。

小心不要写这样的东西,$(...)因为它们会被扩展。

安全的解决方案是引用要评估的字符串:

$ + '45 + (58+3 * l(23))/7'
54.62949752111249272462

$ + '4 * a(1) * 2'
6.28318530717958647688

哪个只是字符比 your 短_bc "6/2",但 a+对我来说似乎更直观。

答案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小部件(映射到Enter)重新定义为用户定义的小部件,该小部件检查当前行是否以数字(十进制或十六进制)开头,可选地以任意数量的(s 为前缀,在其后查找非数字字符以避免误报对于像7zip或 之类的命令411toppm

如果匹配,那么我们将其传递给zcalc(比 bc 更有用,因为它可以使用 shell 变量和所有 zsh 数学函数和数字样式,但不支持任意精度),将该行添加到历史记录并接受空命令。

请注意,如果您在以下内容中输入带有数字的行,可能会导致混乱:

cat << EOF
213 whatever
EOF

或者:

var=(
  123 456
)

答案3

我使用 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

神奇的是别名扩展发生了通常的命令行处理,它允许我们创建一个命令,其其余参数跟随注释字符,实现函数通过历史命令找到该命令。

这个魔法让我可以按字面意思输入*(、 和其他字符。但这也意味着我不能使用 shell 变量,因为$也是字面量:

$ 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 Enter1 + 1Enter Control+D


顺便提一下,我在 中有默认bc设置(如scale),$HOME/.bc并在 别名中使用bc -l。您的使用可能不需要这些修改。

答案4

以下命令行的输入相当简单,

<<< 5+4 bc
<<< 6/3 bc
<<< 7*2 bc

和稍微复杂一点的括号(必须引用或转义),

<<< "(5+4)*2/3" bc
<<< \(5+4\)*2/3 bc

相关内容