Marcel: un shell más moderno para Linux


Marcel es un caparazón nuevo. Es similar a las conchas tradicionales de muchas maneras, pero hace algunas cosas de manera diferente:

  • Piping: All shells use pipes to send a text from the output of one command to the input of another. Marcel pipes structured data instead of strings.
  • Python: Marcel is implemented in Python, and exposes Python in a number of ways. If you need a little bit of logic in your commands, marcel allows you to express it in Python.
  • Scripting: Marcel takes an unusual approach to scripting. You can, of course, simply write a sequence of marcel commands in a text file and execute them. But Marcel also provides an API in the form of a Python module. You can import this module to do Python scripting in a far more convenient way than is possible with plain Python.

Marcel tiene licencia GPLv3.

Instalación de Marcel Modern Shell en Linux

Marcel requiere Python 3.6 o posterior. Ha sido desarrollado y probado en Linux, y principalmente funciona en macOS. (Si desea ayudar con la migración a Windows o solucionar las deficiencias de macOS, póngase en contacto).

Para instalar marcel para su propio uso:

# python3 -m pip install marcel

O si desea instalar para todos los usuarios (por ejemplo, en /usr/local ):

$ sudo python3 -m pip install --prefix /usr/local marcel

Una vez que haya instalado marcel, verifique que esté funcionando ejecutando el comando marcel, y luego en el indicador de marcel, ejecute el comando version:

$ marcel

Personalización de Marcel Shell

Puede personalizar marcel en el archivo ~/.marcel.py , que se lee al inicio (y se vuelve a leer cuando se modifica). Como puede ver por el nombre del archivo, la personalización de marcel se realiza en Python.

Una cosa que probablemente desee hacer es personalizar el mensaje. Para hacer esto, asigne una lista a la variable PROMPT. Por ejemplo, si desea que su mensaje sea el directorio actual, impreso en verde, seguido de > impreso en azul:

PROMPT = [
    Color(0, 4, 0),
    lambda: PWD,
    Color(0, 2, 5),
    '> '
]

El mensaje resultante se ve así:

Esto reemplaza la configuración inescrutable de PS1 que necesitaría hacer en bash. Color (0, 4, 0) especifica verde (los argumentos son valores RGB, en el rango 0-5). PWD es la variable de entorno que representa su directorio actual y anteponer esta variable con lambda: genera una función, evaluada cada vez que se muestra el indicador.

El ~/.marcel.py también puede importar módulos de Python. Por ejemplo, si desea utilizar las funciones del módulo matemático en sus comandos de marcel:

from math import *

Una vez que haya hecho esto, puede consultar los símbolos de ese módulo, p. Ej. pi :

Tenga en cuenta que pi está entre paréntesis. En general, marcel usa paréntesis para delimitar expresiones de Python. Entonces (pi) evalúa la expresión de Python que recupera el valor de la variable pi. También puede acceder a las variables de entorno tradicionales de esta manera, p. Ej. (USUARIO) y (INICIO), o cualquier expresión de Python válida que se base en símbolos en el espacio de nombres de marcel.

Y, por supuesto, puede definir sus propios símbolos. Por ejemplo, si coloca esta definición de función en ~/.marcel.py :

def factorial(n):
    f = 1
    for i in range(1, n + 1):
        f *= i
    return f

entonces puedes usar la función factorial en la línea de comando, p. ej.

Ejemplos de Marcel Shell

Aquí, aprenderemos algunos ejemplos de comandos en el shell de marcel.

Explore el directorio actual de forma recursiva, agrupe los archivos por su extensión (por ejemplo, .txt , .py , etc.) y calcule el tamaño total del archivo para cada grupo.

Puede hacer esto en marcel de la siguiente manera:

El operador ls produce un flujo de objetos File, ( -fr significa visitar directorios de forma recursiva y devolver solo archivos).

Los objetos de archivo se canalizan al siguiente comando, mapa. El mapa especifica una función de Python, en el paréntesis más externo, que asigna cada archivo a una tupla que contiene la extensión del archivo y su tamaño. (Marcel permite que se omita la palabra clave lambda).

El operador rojo (reducir), agrupa por la primera parte de la tupla (extensión) y luego suma los tamaños dentro de cada grupo. El resultado se ordena por extensión.

Las canalizaciones pueden contener una mezcla de operadores marcel y ejecutables de host. Los operadores canalizan objetos, pero en los límites del operador/ejecutable, marcel canaliza cadenas en su lugar.

Por ejemplo, este comando combina operadores y ejecutables y enumera los nombres de usuario de los usuarios cuyo shell es /bin/bash .

$ cat /etc/passwd \
| map (line: line.split(':')) \
| select (*line: line[-1] == '/bin/bash') \
| map (*line: line[0]) \
| xargs echo

cat es un ejecutable de Linux. Lee/etc/passwd, y marcel canaliza su contenido hacia el mapa del operador de marcel.

El argumento entre paréntesis para mapear es una función de Python que divide las líneas en los separadores : , produciendo 7-tuplas. Una selección es un operador de marcel cuyo argumento es una función de Python que identifica esas tuplas en las que el último campo es/bin/bash.

El siguiente operador, otro mapa, mantiene el campo de nombre de usuario de cada tupla de entrada. Finalmente, xargs echo combina los nombres de usuario entrantes en una sola línea, que se imprime en stdout.

Scripting en Marcel Shell

Si bien a veces se considera que Python es un lenguaje de secuencias de comandos, en realidad no funciona bien para ese propósito. El problema es que ejecutar comandos de shell y otros ejecutables de Python es engorroso. Puede usar os.system () , que es simple pero a menudo inadecuado para tratar con stdin, stdout y stderr. subprocess.Popen () es más poderoso pero más complejo de usar.

El enfoque de Marcel es proporcionar un módulo que integre los operadores de Marcel con las características del lenguaje de Python. Para volver a visitar un ejemplo anterior, aquí está el código de Python para calcular la suma de tamaños de archivo por extensión:

from marcel.api import *

for ext, size in (ls(file=True, recursive=True)
                  | map(lambda f: (f.suffix, f.size))
                  | red('.', '+')):
    print(f'{ext}: {size})

Los comandos del shell son los mismos que antes, excepto por convenciones sintácticas. Entonces ls -fr se convierte en ls (file u003d True, recursive u003d True). El mapa y los operadores rojos también están allí, conectados con tuberías, como en la versión de shell. El comando de shell completo (ls ... red) produce un iterador de Python para que el comando se pueda usar con Python para un bucle.

Acceso a la base de datos con Marcel Shell

Puede integrar el acceso a la base de datos con marcel pipelines. Primero, necesita configurar el acceso a la base de datos en el archivo de configuración, ~/.marcel.py , p.

define_db(name='jao',
          driver='psycopg2',
          dbname='acme',
          user='jao')

DB_DEFAULT = 'jao'

Esto configura el acceso a una base de datos de Postgres llamada acme, utilizando el controlador psycopg2. Las conexiones desde marcel se realizarán utilizando el usuario jao, y el perfil de la base de datos se llamará jao. (DB_DEFAULT especifica el perfil de la base de datos jao como el que se utilizará si no se especifica ningún perfil). Con esta configuración realizada, la base de datos ahora se puede consultar utilizando el operador sql, p.

sql 'select part_name, quantity from part where quantity < 10' \
| out --csv –-file ~/reorder.csv

Este comando consulta una tabla llamada part y descarga el resultado de la consulta en el archivo ~/reorder.csv , en formato CSV.

Acceso remoto con Marcel Shell

De manera similar al acceso a la base de datos, el acceso remoto se puede configurar en ~/.marcel.py . Por ejemplo, esto configura un clúster de 4 nodos:

define_remote(name='lab',
              user='frankenstein',
              identity='/home/frankenstein/.ssh/id_rsa',
              host=['10.0.0.100', 
                    '10.0.0.101',
                    '10.0.0.102',
                    '10.0.0.103'])

El clúster se puede identificar como un laboratorio en los comandos de marcel. Los parámetros de identidad y de usuario especifican la información de inicio de sesión y el parámetro de host especifica las direcciones IP de los nodos del clúster.

Una vez que el clúster está configurado, todos los nodos se pueden operar a la vez. Por ejemplo, para obtener una lista de pids de proceso y líneas de comando en todo el clúster:

@lab [ps | map (proc: (proc.pid, proc.commandline))]

Esto devuelve un flujo de tuplas (dirección IP, PID, línea de comando).

Para más información visite:

Marcel es bastante nuevo y está en desarrollo activo. Póngase en contacto si desea ayudar.