有时我需要运行一些数学运算。我知道我可以使用bc
or 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