Marcel - Et mer moderne skall for Linux


Marcel er et nytt skall. Det ligner på tradisjonelle skjell på mange måter, men det gjør noen ting annerledes:

  • Rørføring: Alle skjell bruker rør for å sende en tekst fra utdataene fra én kommando til inngangen til en annen. Marcel sender strukturerte data i stedet for strenger.
  • Python: Marcel er implementert i Python, og avslører Python på en rekke måter. Hvis du trenger litt logikk i kommandoene dine, lar marcel deg uttrykke det i Python.
  • Skript: Marcel har en uvanlig tilnærming til skripting. Du kan selvfølgelig ganske enkelt skrive en sekvens av marcel-kommandoer i en tekstfil og utføre dem. Men Marcel gir også en API i form av en Python-modul. Du kan importere denne modulen for å gjøre Python-skripting på en langt mer praktisk måte enn det som er mulig med vanlig Python.

Marcel er lisensiert under GPLv3.

Installerer Marcel Modern Shell i Linux

Marcel krever Python 3.6 eller nyere. Det er utviklet og testet på Linux, og det fungerer stort sett på macOS. (Hvis du vil hjelpe portering til Windows, eller for å fikse macOS-manglene, ta kontakt.)

Slik installerer du marcel for eget bruk:

python3 -m pip install marcel

Eller hvis du vil installere for alle brukere (f.eks. til /usr/local):

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

Når du har installert marcel, sjekk at det fungerer ved å kjøre kommandoen marcel, og deretter ved marcel-ledeteksten, kjør versjonen kommando:

marcel

Tilpasning av Marcel Shell

Du kan tilpasse marcel i filen ~/.marcel.py, som leses ved oppstart (og leses på nytt når den endres). Som du kan se fra filens navn, gjøres tilpasning av marcel i Python.

En ting du sannsynligvis vil gjøre er å tilpasse forespørselen. For å gjøre dette, tilordner du en liste til PROMPT-variabelen. Hvis du for eksempel vil at ledeteksten skal være gjeldende katalog, trykket i grønt, etterfulgt av > trykket i blått:

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

Den resulterende ledeteksten ser slik ut:

Dette erstatter den uoversiktlige PS1-konfigurasjonen som du må gjøre i bash. Farge(0, 4, 0) angir grønn, (argumentene er RGB-verdier, i området 0-5 sterk>). PWD er miljøvariabelen som representerer din nåværende katalog og prefiks til denne variabelen med lambda: genererer en funksjon som evalueres hver gang ledeteksten vises.

~/.marcel.py kan også importere Python-moduler. Hvis du for eksempel vil bruke funksjonene til matematikkmodulen i marcel-kommandoene dine:

from math import *

Når du har gjort dette, kan du referere til symboler fra den modulen, f.eks. pi:

Merk at pi er i parentes. Generelt bruker marcel parenteser for å avgrense Python-uttrykk. Så (pi) evaluerer Python-uttrykket som henter verdien til variabelen pi. Du kan også få tilgang til tradisjonelle miljøvariabler på denne måten, f.eks. (USER) og (HOME), eller et hvilket som helst gyldig Python-uttrykk som er avhengig av symboler i marcels navneområde.

Og du kan selvfølgelig definere dine egne symboler. Hvis du for eksempel setter denne funksjonsdefinisjonen i ~/.marcel.py:

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

så kan du bruke faktoriell funksjon på kommandolinjen, f.eks.

Marcel Shell Eksempler

Her vil vi lære noen eksempler på kommandoer i marcel-skallet.

Finn filstørrelser etter utvidelse

Utforsk gjeldende katalog rekursivt, grupper filene etter filtypen (f.eks. .txt, .py og så videre), og beregne den totale filstørrelsen for hver gruppe.

Du kan gjøre dette i marcel som følger:

ls-operatøren produserer en strøm av filobjekter, (-fr betyr besøk kataloger rekursivt, og returner kun filer).

Fil-objektene sendes til neste kommando, kart. Kartet spesifiserer en Python-funksjon, i ytterste parentes, som tilordner hver fil til en tuppel som inneholder filens filtype, og dens størrelse. (Marcel lar lambda-nøkkelordet utelates.)

Operatoren rød (reduser) grupperer etter den første delen av tuppelen (utvidelsen) og summerer deretter størrelsene i hver gruppe. Resultatet er sortert etter utvidelse.

Host Executables og Marcel Pipeline

Rørledninger kan inneholde en blanding av marcel-operatorer og kjørbare vertsfiler. Operatører rør objekter, men ved operatør/kjørbare grenser, marcel pipes strenger i stedet.

For eksempel kombinerer denne kommandoen operatører og kjørbare filer og viser brukernavnene til brukere hvis skall er /bin/bash.

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

cat er en kjørbar Linux-fil. Den leser /etc/passwd, og marcel sender innholdet nedstrøms til marcel-operatørkartet.

Argumentet i parentes som skal kartlegges er en Python-funksjon som deler linjene ved :-separatorene, og gir 7-tupler. En select er en marcel-operator hvis argument er en Python-funksjon som identifiserer de tuplene der det siste feltet er /bin/bash.

Den neste operatøren, et annet kart, beholder brukernavnfeltet til hver inndatatuppel. Til slutt kombinerer xargs echo de innkommende brukernavnene til en enkelt linje, som skrives ut til stdout.

Manus i Marcel Shell

Mens Python noen ganger anses å være et skriptspråk, fungerer det faktisk ikke bra for det formålet. Problemet er at det er tungvint å kjøre skallkommandoer og andre kjørbare filer fra Python. Du kan bruke os.system(), som er enkelt, men ofte utilstrekkelig for å håndtere stdin, stdout og stderr. subprocess.Popen() er kraftigere, men mer komplisert å bruke.

Marcels tilnærming er å tilby en modul som integrerer marcel-operatører med Pythons språkfunksjoner. For å gå tilbake til et tidligere eksempel, her er Python-koden for å beregne summen av filstørrelser etter utvidelse:

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

Skallkommandoene er de samme som før, bortsett fra syntaktiske konvensjoner. Så ls -fr blir til ls(file=True, recursive=True). Kartet og røde operatører er der også, forbundet med rør, som i skallversjonen. Hele skallkommandoen (ls … red) gir en Python-iterator slik at kommandoen kan brukes med Python for en løkke.

Databasetilgang med Marcel Shell

Du kan integrere databasetilgang med marcel-rørledninger. Først må du konfigurere databasetilgang i konfigurasjonsfilen, ~/.marcel.py, f.eks.

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

DB_DEFAULT = 'jao'

Dette konfigurerer tilgang til en Postgres-database kalt acme, ved å bruke psycopg2-driveren. Tilkoblinger fra marcel vil gjøres ved å bruke jao-brukeren, og databaseprofilen heter jao. (DB_DEFAULT spesifiserer jao-databaseprofilen som den som skal brukes hvis ingen profil er spesifisert.) Med denne konfigurasjonen utført, kan databasen nå spørres ved hjelp av sql-operatoren, f.eks.

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

Denne kommandoen spør etter en tabell kalt del, og dumper søkeresultatet inn i filen ~/reorder.csv, i CSV-format.

Fjerntilgang med Marcel Shell

I likhet med databasetilgang kan fjerntilgang konfigureres i ~/.marcel.py. For eksempel konfigurerer dette en 4-node klynge:

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

Klyngen kan identifiseres som en lab i marcel-kommandoer. Bruker- og identitetsparameterne spesifiserer påloggingsinformasjon, og parameteren vert spesifiserer IP-adressene til nodene i klyngen.

Når klyngen er konfigurert, kan alle noder betjenes samtidig. For eksempel, for å få en liste over prosess pids og kommandolinjer på tvers av klyngen:

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

Dette returnerer en strøm av (IP-adresse, PID, kommandolinje) tupler.

For mer informasjon besøk:

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

Marcel er ganske ny og under aktiv utvikling. Ta kontakt hvis du ønsker å hjelpe.