時々私はいくつかの数学演算を実行する必要があります。 bc
またはecho $(( 6/2 ))
を使用できることはわかっています。 bc
が入力を読み取るための独自の関数を作成しました。ただし、次のように入力するのに時間がかかることがあります:_bc "6/2"
。だから私はこの質問があります:
コマンドラインで数値の数学演算を実行する方法をzsh/bashに教える方法はありますか? 1つの例は、数千を超える単語です。
$ 6/2
$ 3.0
これは、zsh/bashが番号を認識し、つまりbcを呼び出す必要があることを意味します。
Bashでは、readlineユーティリティを使用して、Word 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 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"
_よりも2つ文字だけ短いですが、_+
_は私にとってより直感的に見えます。
私は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
魔法は、エイリアス展開が通常のコマンドライン処理の前にbefore行われるという事実です。これにより、残りの引数がコメント文字の後に続くコマンドを作成できます。実装機能は、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
エイリアスで。これらの変更は必要ありません。
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をプレフィックスとして付けられた数値(10進数または16進数)で始まるかどうかをチェックするユーザー定義のウィジェットに、その後に非数字文字を探して、 7Zip
または411toppm
。
それが一致する場合は、zcalc
に渡します(シェル変数とすべてのzsh数学関数および数値スタイルを使用できますが、任意の精度をサポートしていないため、bcよりも便利です)、履歴に行を追加し、空のコマンドを受け入れます。
次のような数字を含む行を入力すると、混乱が生じる可能性があることに注意してください。
cat << EOF
213 whatever
EOF
または:
var=(
123 456
)
Stéphaneのzshの回答 に触発され、合計で Isaacのbshの回答 より長いが、操作は短い:
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
実行する予定の操作によっては、正規表現を厳しくすることができます。
これは、特定のコマンドが存在しない場合にERRトラップを呼び出すというbash動作を使用します。最後のコマンド($_
)に数字が含まれている場合、その「コマンド」に対してbc
を実行します。
Stéphaneからのヒント のおかげで、結果を達成するための少しクリーンな方法をここに示します(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の終了コードを返します。
次のコマンドラインは入力がかなり簡単です。
<<< 5+4 bc
<<< 6/3 bc
<<< 7*2 bc
かっこで少し複雑です(引用符またはエスケープする必要があります)。
<<< "(5+4)*2/3" bc
<<< \(5+4\)*2/3 bc
Bashでこれを行うもう1つの不完全な方法は、すべてのコマンドで実行されるDEBUG
トラップを使用することです。 extdebug
を設定すると、トラップハンドラーがメインコマンドの実行を阻止できるため、「コマンドが見つかりません」エラーが発生しません。
$ 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
トラップは、変数またはファイル名のパターンを展開する前に完全なコマンドラインを取得するため、引用符で囲まれていない*
機能します。 (しかし、計算でシェル変数を使用しても機能しません。)
ただし、引用符で囲まれていない括弧は構文エラーを引き起こすため、これも完全ではありません。
(上記の正規表現に Stéphane's answer からニックネームを付けました。)
Exprはどうですか?
$ expr 6 / 2
3