Pesquisa de site

Marcel – Um Shell Mais Moderno para Linux


Marcel é uma nova concha. É semelhante aos shells tradicionais em muitos aspectos, mas faz algumas coisas de maneira diferente:

  • Piping: Todos os shells usam pipes para enviar um texto da saída de um comando para a entrada de outro. Marcel canaliza dados estruturados em vez de strings.
  • Python: Marcel é implementado em Python e expõe o Python de diversas maneiras. Se você precisar de um pouco de lógica em seus comandos, marcel permite expressá-la em Python.
  • Scripting: Marcel adota uma abordagem incomum para scripts. Você pode, é claro, simplesmente escrever uma sequência de comandos do Marcel em um arquivo de texto e executá-los. Mas Marcel também fornece uma API na forma de um módulo Python. Você pode importar este módulo para executar scripts Python de uma maneira muito mais conveniente do que é possível com Python simples.

Marcel é licenciado sob GPLv3.

Instalando Marcel Modern Shell no Linux

Marcel requer Python 3.6 ou posterior. Ele foi desenvolvido e testado em Linux e funciona principalmente em macOS. (Se você quiser ajudar a migrar para o Windows ou corrigir as deficiências do macOS, entre em contato.)

Para instalar marcel para seu próprio uso:

python3 -m pip install marcel

Ou se você deseja instalar para todos os usuários (por exemplo, para /usr/local):

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

Depois de instalar o marcel, verifique se ele está funcionando executando o comando marcel e, em seguida, no prompt do marcel, execute a versão comando:

marcel

Personalização de Marcel Shell

Você pode personalizar marcel no arquivo ~/.marcel.py, que é lido na inicialização (e relido quando modificado). Como você pode perceber pelo nome do arquivo, a customização do marcel é feita em Python.

Uma coisa que você provavelmente deseja fazer é personalizar o prompt. Para fazer isso, você atribui uma lista à variável PROMPT. Por exemplo, se você deseja que seu prompt seja o diretório atual, impresso em verde, seguido de > impresso em azul:

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

O prompt resultante é assim:

Isso substitui a configuração inescrutável do PS1 que você precisaria fazer no bash. Color(0, 4, 0) especifica verde, (os argumentos são valores RGB, no intervalo 0-5). PWD é a variável de ambiente que representa seu diretório atual e prefixar esta variável com lambda: gera uma função, avaliada cada vez que o prompt é exibido.

O ~/.marcel.py também pode importar módulos Python. Por exemplo, se você quiser usar as funções do módulo matemático em seus comandos marcel:

from math import *

Depois de fazer isso, você pode consultar os símbolos desse módulo, por exemplo. pi:

Observe que pi está entre parênteses. Em geral, marcel usa parênteses para delimitar expressões Python. Portanto (pi) avalia a expressão Python que recupera o valor da variável pi. Você também pode acessar variáveis de ambiente tradicionais dessa forma, por exemplo. (USER) e (HOME), ou qualquer expressão Python válida que dependa de símbolos no namespace de marcel.

E você pode, claro, definir seus próprios símbolos. Por exemplo, se você colocar esta definição de função em ~/.marcel.py:

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

então você pode usar a função fatorial na linha de comando, por exemplo.

Exemplos de Marcel Shell

Aqui, aprenderemos alguns exemplos de comandos no shell marcel.

Encontre tamanhos de arquivo por extensão

Explore o diretório atual recursivamente, agrupe os arquivos por extensão (por exemplo, .txt, .py e assim por diante) e calcule o tamanho total do arquivo para cada grupo.

Você pode fazer isso no Marcel da seguinte maneira:

O operador ls produz um fluxo de objetos File (-fr significa visitar diretórios recursivamente e retornar apenas arquivos).

Os objetos Arquivo são canalizados para o próximo comando, map. O map especifica uma função Python, entre parênteses externos, que mapeia cada arquivo para uma tupla contendo a extensão do arquivo e seu tamanho. (Marcel permite que a palavra-chave lambda seja omitida.)

O operador vermelho (reduzir) agrupa pela primeira parte da tupla (extensão) e então soma os tamanhos dentro de cada grupo. O resultado é classificado por extensão.

Host Executáveis e Marcel Pipeline

Pipelines podem conter uma mistura de operadores marcel e executáveis de host. Os operadores canalizam objetos, mas nos limites do operador/executável, marcel canaliza strings.

Por exemplo, este comando combina operadores e executáveis e lista os nomes de usuário dos usuários cujo shell é /bin/bash.

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

cat é um executável do Linux. Ele lê /etc/passwd e marcel canaliza seu conteúdo downstream para o mapa do operador marcel.

O argumento entre parênteses para mapear é uma função Python que divide as linhas nos separadores :, produzindo 7 tuplas. Um select é um operador marcel cujo argumento é uma função Python que identifica as tuplas nas quais o último campo é /bin/bash.

O próximo operador, outro mapa, mantém o campo de nome de usuário de cada tupla de entrada. Finalmente, xargs echo combina os nomes de usuário recebidos em uma única linha, que é impressa em stdout.

Scripts em Marcel Shell

Embora Python às vezes seja considerado uma linguagem de script, na verdade ele não funciona bem para esse propósito. O problema é que executar comandos shell e outros executáveis do Python é complicado. Você pode usar os.system(), que é simples, mas muitas vezes inadequado para lidar com stdin, stdout e stderr. subprocess.Popen() é mais poderoso, mas mais complexo de usar.

A abordagem de Marcel é fornecer um módulo que integre os operadores Marcel com os recursos da linguagem Python. Para revisitar um exemplo anterior, aqui está o código Python para calcular a soma dos tamanhos de arquivo por extensão:

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})

Os comandos shell são os mesmos de antes, exceto pelas convenções sintáticas. Então ls -fr se transforma em ls(file=True, recursive=True). O mapa e os operadores vermelhos também estão lá, conectados por tubos, como na versão shell. Todo o comando shell (ls… red) produz um iterador Python para que o comando possa ser usado com um loop for do Python.

Acesso ao banco de dados com Marcel Shell

Você pode integrar o acesso ao banco de dados com pipelines do Marcel. Primeiro, você precisa configurar o acesso ao banco de dados no arquivo de configuração, ~/.marcel.py, por exemplo.

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

DB_DEFAULT = 'jao'

Isso configura o acesso a um banco de dados Postgres chamado acme, usando o driver psycopg2. As conexões do marcel serão feitas usando o usuário jao, e o perfil do banco de dados é denominado jao. (DB_DEFAULT especifica o perfil do banco de dados jao como aquele a ser usado se nenhum perfil for especificado.) Com esta configuração feita, o banco de dados agora pode ser consultado usando o operador sql, por exemplo.

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

Este comando consulta uma tabela chamada part e despeja o resultado da consulta no arquivo ~/reorder.csv, no formato CSV.

Acesso Remoto com Marcel Shell

Da mesma forma que o acesso ao banco de dados, o acesso remoto pode ser configurado em ~/.marcel.py. Por exemplo, isso configura um cluster de 4 nós:

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'])

O cluster pode ser identificado como um laboratório nos comandos marcel. Os parâmetros de usuário e identidade especificam informações de login e o parâmetro host especifica os endereços IP dos nós no cluster.

Depois que o cluster estiver configurado, todos os nós poderão ser operados de uma só vez. Por exemplo, para obter uma lista de pids de processos e linhas de comando no cluster:

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

Isso retorna um fluxo de tuplas (endereço IP, PID, linha de comando).

Para mais informações visite:

  • https://www.marceltheshell.org/
  • https://github.com/geophile/marcel

Marcel é bastante novo e está em desenvolvimento ativo. Entre em contato se quiser ajudar.