Contas rápidas no terminal


Boas, xente.

A semana pasada pasei por un comentario en HN do 2019. O usuario estaba experimentando cuns script pra facer algunhas contas directamente no terminal bash.

TLDR: Clica aquí pra saltar a historia e ir directamente ao código.

O que o usuario propoñía era usar algo coma isto, baseado no comando dc (os comentarios son meus).

$ . calc.sh  # Cargar funcións
$ * 4 5      # Multiplica 4 e 5
20
$ / 21 3     # Divide 21 por 3
7

Isto soaba interesante. Persoalmente, cando teño que facer algunhas contas abro un terminal e invoco ao Python, e facelo directamente sen ter que lanzar Python parecía útil.

Pero, se tivera que facer un cambio pequeno… a algunha xente lle resulta intuitiva a notación Polaca , pero pra isto preferiría ter unha notación mais habitual. Algo coma:

$ C 4 * 5
20
$ C 21 / 3
7

Esa e a idea, o comando se chamaría C e os argumentos deben ser o mais naturais posible.

O xeito máis sinxelo de facelo é escreber unha función bash que invoque o interprete de Python de transparentemente, algo coma…

C () {
  python -c "print($*)"
}

Pero hai un problema! Con isto podemos facer algunhas contas, pero os produtos (*) serían expandidos a nomes de ficheiros:

# Simulemos un directorio con algúns ficheiros
$ mkdir test
$ cd test
$ touch fname1
$ touch fname2
# Se invocamos a función, o '*' será reemplazado por nomes de ficheiro
$ C 4 * 5
  File "<string>", line 1
    print(4 fname1 fname2 5)
            ^
SyntaxError: invalid syntax

Podemos pensar en desactivar a expansión dentro da nosa función. Pero a expansión ocorre antes de que o comando se execute, así que non podemos solucionalo dentro da función.

Algo que semella unha función, e que pode facer cousas antes de expandir os argumentos e un alias.

__calc () {
  python -c "print($*)"
  set +f  # Re-activar a expansión de ficheiros
}

alias C='set -f; __calc '

De este xeito, o alias executa set -f, e con isto desactiva a expansión, antes de que se evalúen os argumentos de función __calc.

$ C 4 * 5
20
$ echo *
fname1 fname2

Vale, agora imos probar a importar a libraría matemática de Python

__calc () {
  python -c "from math import *; print($*)"
  set +f  # Re-activar a expansión de ficheiros
}

alias C='set -f; __calc '

E usémola pra facer algúns cálculos:

$ C sqrt( 999 )
bash: syntax error near unexpected token `('

Vaia, iso non pinta ben. Veredes, en bash o carácter ( é interpretado coma o comezo dunha subshell, e isto (ao contrario da expansión dos nomes de ficheiro) non pode ser deshabilitado.

Pra ser honesto, non atopei unha solución pra isto, pero podo ofrecervos dúas opcións:

Primeira, simplemente usemos comiñas:

$ C "sqrt( 999 )"
31.606961258558215

A outra e aceptar os parámetros con outros caracteres, que reemplazaremos por parénteses []():

Resultado

__calc () {
  local __calc_CMD=$(echo "$*"|tr "[]" "()")
  python -c "from math import *; print($__calc_CMD)"
  set +f  # Re-activar a expansión de ficheiros
}

alias C='set -f; __calc '

E con isto xa podemos facer os cálculos directamente no terminal:

$ C sqrt [ 3 + [ 3 * 4 ] / 2 ]
3.0

Iso é todo, ahí queda a idea. Leémonos!

comments powered by Disqus