Marcel是一个新的Shell。它在许多方面与传统的shell相似,但是在功能上有所不同:
- 管道:所有Shell程序都使用管道将文本从一个命令的输出发送到另一个命令的输入。Marcel用管道传输结构化数据而不是字符串。
- Python:Marcel是用Python实现的,并以多种方式公开Python。如果您的命令中需要一点逻辑,可以使用marcel用Python表示它。
- 脚本编写:Marcel采用了一种不寻常的脚本编写方法。当然,您可以简单地在文本文件中编写一系列marcel命令并执行它们。但是Marcel还提供了Python模块形式的API。您可以导入该模块以比普通Python更加方便的方式执行Python脚本编写。
Marcel已获得GPLv3许可。
在Linux中安装Marcel Modern Shell
Marcel需要Python 3.6或更高版本。它已经在Linux上进行了开发和测试,并且主要在macOS上运行。(如果您想帮助移植到Windows或修复macOS的缺陷,请联系。)
要安装marcel以供您自己使用:
linuxmi@linuxmi:~/www.linuxmi.com$ python3 -m pip install marcel
或者,如果您想为所有用户安装(例如,至/usr/local
):
linuxmi@linuxmi:~/www.linuxmi.com$ sudo python3 -m pip install --prefix /usr/local marcel
一旦安装了marcel,请通过运行marcel命令检查其是否正常运行,然后在marcel提示符下运行version命令:
linuxmi@linuxmi:~/www.linuxmi.com$ marcel /home/linuxmi/www.linuxmi.com $ version 0.10.7

检查Marcel Shell版本
定制Marcel Shell
您可以自定义文件中的marcel,该文件~/.marcel.py
在启动时会读取(修改后会重新读取)。从文件名可以看出,marcel的自定义是在Python中完成的。
您可能想做的一件事是自定义提示。为此,您将一个列表分配给PROMPT变量。例如,如果希望您的提示成为当前目录,则以绿色打印,然后>
以蓝色打印:
PROMPT = [ Color(0, 4, 0), lambda: PWD, Color(0, 2, 5), '> ' ]
结果提示如下:

这将替代PS1
您需要在bash中进行的难以理解的配置。Color(0,4,0)指定green,(参数为RGB值,范围为0-5)。PWD是代表您当前目录的环境变量,并在此变量之前添加lambda:
一个函数,该函数在每次显示提示时都会进行评估。
该~/.marcel.py
还可以导入Python模块。例如,如果要在marcel命令中使用math模块的功能:
from math import *
完成此操作后,您可以引用该模块中的符号,例如pi
:

请注意,pi
用括号括起来。通常,marcel使用括号来分隔Python表达式。因此,(pi)
对检索变量pi的值的Python表达式求值。您还可以通过这种方式访问传统的环境变量,例如(USER)和(HOME),或任何依赖于marcel命名空间中符号的有效Python表达式。
当然,您可以定义自己的Symbols(符号表)。例如,如果将此函数定义放在~/.marcel.py
:
def factorial(n): f = 1 for i in range(1, n + 1): f *= i return f
然后您可以在命令行上使用阶乘函数factorial,例如
/home/linuxmi/www.linuxmi.com> (factorial(20))
2432902008176640000

Marcel Shell的例子
在这里,我们将学习marcel shell中的一些命令示例。
按扩展名查找文件大小
递归浏览当前目录,按文件扩展名对文件进行分组(例如.txt
,.py
依此类推),然后计算每个组的总文件大小。
linuxmi@linuxmi:~/www.linuxmi.com$ marcel /home/linuxmi/www.linuxmi.com> ls -fr \ /home/linuxmi/www.linuxmi.com + | map (file: (file.suffix, file.size)) \ /home/linuxmi/www.linuxmi.com + | red . + \ /home/linuxmi/www.linuxmi.com + | sort
您可以按以下方式进行处理:

按扩展名查找文件大小
该ls操作符生成文件对象流,(-fr
表示递归访问目录,只返回文件)。
该file对象被输送到下一个命令map。该map在最外面的括号中指定了一个Python函数,该函数将每个文件映射到一个包含文件扩展名及文件大小的元组。(Marcel允许省略lambda关键字。)
red (reduce)运算符根据元组(扩展)的第一部分进行分组,然后对每个组内的大小进行求和。结果按扩展排序。
主机可执行文件和Marcel管道
管道可以混合包含marcel运算符和主机可执行文件。运算符通过管道传递对象,但在运算符/可执行文件的边界,以marcel代替字符串。
例如,这个命令组合了操作符和可执行文件,并列出shell为/bin/bash
用户的用户名。
$ cat /etc/passwd \ | map (line: line.split(':')) \ | select (*line: line[-1] == '/bin/bash') \ | map (*line: line[0]) \ | root linuxmi jenkins

cat是一个Linux可执行文件。它读取/etc/passwd,然后marcel将其内容传输到下游的marcel操作符映射。
map的圆括号参数是一个Python函数,它在:分隔符处拆分行,生成7元组。select是一个marcel操作符,它的参数是一个Python函数,用于标识最后一个字段为/bin/bash的那些元组。
下一个运算符,另一个map保留每个输入元组的用户名字段。最后,xargs echo将输入的用户名合并为一行,并打印输出到屏幕。
Marcel Shell中的脚本编写
虽然Python有时被认为是一种脚本语言,但实际上它并不能很好地实现这一目的。问题是运行shell命令和Python的其他可执行程序很麻烦。您可以使用os.system()
,它很简单,但通常不足以处理stdin,stdout和stderr。subprocess.Popen()
功能更强大,但使用起来更复杂。
Marcel的方法是提供一个模块,该模块集成了Marcel运算符和Python的语言特性。回到前面的例子,下面是Python代码,用于按扩展名计算文件大小的总和:
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})
除了语法约定外,shell命令与以前的命令相同。因此ls -fr
变成ls(file=True, recursive=True。映射和red运算符也在那里,并通过管道连接,就像在shell版本中一样。整个shell命令(ls…red)产生一个Python迭代器,因此该命令可以与Python一起使用来进行循环。
使用Marcel Shell进行数据库访问
您可以将数据库访问与marcel管道集成在一起。首先,您需要在config文件中配置数据库访问~/.marcel.py
,例如
define_db(name='linuxmi', driver='psycopg2', dbname='acme', user='linuxmi') DB_DEFAULT = 'linuxmi'
这将使用psycopg2驱动程序配置对名为acme的Postgres数据库的访问。来自marcel的连接将使用linuxmi用户进行,数据库配置文件名为linuxmi。(如果未指定概要文件,则DB_DEFAULT将linuxmi数据库概要文件指定为要使用的概要文件。)完成此配置后,现在可以使用sql运算符查询数据库。
sql 'select part_name, quantity from part where quantity < 10' \ | out --csv –-file ~/linuxmi.csv
此命令查询名为part的表,并将查询结果~/linuxmi.csv
以CSV格式转储到文件中。
使用Marcel Shell进行远程访问
与数据库访问类似,可以在中配置远程访问~/.marcel.py
。例如,这配置了一个4节点集群:
define_remote(name='lab', user='linuxmi', identity='/home/linuxmi/.ssh/id_rsa', host=['192.168.1.100', '192.168.1.101', '192.168.1.102', '192.168.1.103'])
可以在marcel命令中将集群标识为lab。用户和身份参数指定登录信息,host参数指定集群上节点的IP地址。
一旦配置了群集,即可立即操作所有节点。例如,要获取集群中的进程pid和命令行的列表:
@lab [ps | map (proc: (proc.pid, proc.commandline))]
这将返回(IP地址,PID,命令行)元组的流。
有关更多信息,请访问:
Marcel目前正在积极开发中。如果你愿意帮忙,请与我们联系。