Xonsh简明教程
- 翻译文档地址: https://xon.sh/tutorial.html
- 非严谨翻译,仅作记录参考
Starting xonsh 开始使用
安装好xonsh之后,输入xonsh
即可,
Basic 基础用法
xonsh基于python语言,因此也可使用python解释器执行,基本功能与pythonshell
相同
Environment variables 环境变量
使用$
来定义环境变量,如$HOME
,但在更新os.environ
时,需要设置$UPDATE_OS_ENVIRONEMNT
为true
>>> $GOAL = "hello"
>>> pint($GOAL)
The environment itself ${...}
环境变量本身
所有环境变量可以使用${...}
来访问,也可用__xonsh__.env
, 可以以in
关键词判断是否设置某一个环境变量;可使用${...}.swap(VARIABLE="specific name")
,来设置临时变量。
>>> 'HOME' in ${...}
True
>>> with ${...}.swap(SOMEVAR="foo"):
echo $SOMEVAR
foo
>>> echo $SOMEVAR
Environment lookup with ${}
访问环境变量
访问环境变量的2种方式:
- 知道环境变量名,使用
$HOME
- 需组合环境变变量名,如
${"ho"+"me"}
Environment types 环境变量类型
xonsh中shell
环境变量被python
访问时,也有存在类型,如list
,int
,dict
等
-
\w*PATH
,任何以PATH
结尾的变量名,类型为list
-
\w*DIRS
,任何以DIRS
结尾的变量名,类型为list
-
XONSH_HISTORY_SIZE
,这种变量类型为int
-
CASE_SENSITIVE_COMPLETIONS
,这种变量类型为bool
在子进程模式中,试图访问一个不存在的变量将返回空字符串;
在python解释模式,试图访问一个不存在环境变量,将引发KeyError
Running commands 运行命令
与在普通shell
中使用的基本方式及功能相同
Python-mode vs Subprocess-mode python解释模式与子进程模式
如何区分所在代码的运行模式很重要,但由于一些很像Python
的操作的符shell
命令存在,在运行时可能会存在歧义。
对于任何包含表达式的代码,如果在当前所有变量中找不到定义,则会使用子进程模型运行;
如果上述2种模式出错,将选择python解释模式,但通常都被处理的很好。
如果想明确使用子进程模式运行代码,则可以使用正式的
xonsh
标示该模式运行的语法,如![ls -l]
>>> ls -l
total 0
>>> ls, l = 2, 1
>>> ls -l
1
>>> del ls
>>> ls -l
total 0
Quoting 引号使用
单引号及双引号可用于去除某些代码的潜在含义,如果在子进程模式中包含了一些与xonsh
语法冲突的字符,则必须使用引号来标示xonsh
不解释该字符;
在xonsh
中不存在转义字符的概念,如\
。
>>> echo ${
SyntaxError ...
>>> ehco '${'
${
Captured subprocess with $()
and !()
捕获子进程输出
使用$(
可在子进程模式中运行代码,并且捕获有关输出信息;
-
使用
$()
可捕获并返回子进程模式下运行的标准输出,并且作为python字符串返回出来,这与$()
在bash中用法相同;>>> $(ls -l) "total 0\n -..."
-
使用
!()
则会捕获有关命令的更多信息,并且返回的是python中CommandPipeline
实例,能够程序运行的返回码、进行id、标准输出与标准错误,以及程序输入输出是怎样被重定向的;>>> !(ls .) CommandPipeline(stdin=<_io.BytesIO object ...)
该实例化对象在返回状态为0时代表
truthy
,可以使用==
判断,这样的用法允许了新的交互类型;# pign到谷歌返回信息时才会跳出循环 >>>while not !(ping -c 1 google.com): sleep 1
该实例化对象,也可使用迭代的方法,这会输出一行一行的程序结果,这可以干净快速地处理程序输出;除此之外,该实例化对象还包含
itercheck
用法,在返回状态码非0时,将引发XonshCalledProcessError
>>> for line in !(nmcli device): dev, typ, state, conn_name = line.split(None, 3) if typ == 'wifi' and state == 'connected': return dev
$()
和!()
同样也是表达式,可使用变量赋值、访问属性等;也可以与$HOME
等结合使用;>>> $(echo $HOME) "/home/peanut\n"
但
Job control
在捕获子进程输出中不能用~
Uncaptured subprocess with $[]
and ![]
非捕获子进程
使用$[]
命令,代码在子进程模式下运行后,会把结果输出到屏幕,但实际返回None
;
>>> x = $[ls -l]
total 0
...
>>> x is None
True
使用![]
命令,会将代码在子程序模式运行的标准输出与标准错误输出到屏幕,但实际返回None
>>> x = ![ls -l] and ![echo "hi"]
total 0
...
hi
>>> x is None
True
Python evalution with @()
使用python创建并运行命令
使用@(
操作符,会以Python解释运行()
中的代码,并在子进程模式运行 ;python输出结果添加至subprocess command list
中,之后在子进程模式中运行;
如果python输出结果是字符串或
bytes
,结果会被追加至参数列表中返回;如果python输出结果是列表或非字符串序列,结果会被转换至字符串,并且依次追加至参数列表中返回;
-
如果python输出结果的第一位是函数,结果将被会处理为
alias
,(即时没有被添加至aliases
中),否则结果会被转换成字符串追加至参数列表中。>>> x, y = 'xonsh', 'party' >>> echo @(x + ' ' + y) xonsh party >>> echo @(2+2) 4 >>> echo @([42, 'yo']) 42 yo >>> echo "hello" | @(lambda a, s=None: s.read().strip() + " world\n") hello world >>> @(['echo', 'hello', 'world']) hello world >>> # note that strings are not split automatically >>> @('echo hello world') xonsh: subprocess mode: command not found: echo hello world
-
该关键词能够被嵌套在捕获或非捕获操作符中,and generate any of the tokens in the subprocess command list.
>>> out = $(echo @(x + ' ' + y)) >>> out 'xonsh party\n' >>> @("ech" + "o") "hey" hey
-
因此,
@()
操作符可以使用python-code去创建并运行复杂的shell命令;>>> for i in range(20): $[touch @('file%02d' % i)]
-
@()
操作符也可以直接用在子进程的参数中,而非仅作为单独的参数;>>> x = 'hello' >>> echo /path/to/@(x) /path/to/hello
-
当
@(
操作符被用在子进程参数中,并且)
是一个非字符串的迭代类型,@()
将会自动迭代所有可能的值。>>> echo /path/to/@(['hello', 'world']) /path/to/hello /path/to/world >>> echo @(['a', 'b']):@('x', 'y') a:x a:y b:x b:y
Command substitution with @$()
命令替换
操作符$()
和@()
允许命令
输出替换命令本身,比如@([i.strip() for i in $(cmd).split()])
,但是xonsh提供了一个简答的写法:
>>> # this returns a string representing stdout
>>> $(which ls)
'ls --color=auto\n'
>>> # this attempts to run the command, but as one argument
>>> # (looks for 'ls --color=auto\n' with spaces and newline)
>>> @($(which ls).strip())
xonsh: subprocess mode: command not found: ls --color=auto
>>> # this actually executes the intended command
>>> @([i.strip() for i in $(which ls).split()])
some_file some_other_file
>>> # this does the same thing, but is much more concise
>>> @$(which ls)
some_file some_other_file
Nesting subprocess 嵌套子进程
滥用该系列命名可能导致未知后果,操作符包含$()
、$[]
、${}
、@()
、@$()
;
操作符$()
与$[]
可以嵌套使用,是由于这些作符内部均在子进程模式下运行,而由于@()
与${}
是在Python模式下执行的,所以不可能在其中嵌套其他子进程操作符;
>>> ls -l
total 0
...
>>> >>> $[@$(which @($(echo ls).strip())) @('-' + $(printf 'l'))]
total 0
...
为了跟踪上述过程,可以开始$XONSH_TRACE_SUBPROCESS=True
>>> $XONSH_TRACE_SUBPROC = True
>>> $[@$(which @($(echo ls).strip())) @('-' + $(printf 'l'))]
TRACE SUBPROC: (['echo', 'ls'],)
TRACE SUBPROC: (['which', 'ls'],)
TRACE SUBPROC: (['printf', 'l'],)
TRACE SUBPROC: (['ls', '--color=auto', '-v', '-l'],)
total 0
...
Pipes 管道
在子进程模式下,xonsh允许使用|
去连接其他命令;但在python模式下|
也是操作符,
>>> env | uniq | sort | grep PATH
...
Logical subprocess and 逻辑子进程and
在子进程模式下允许使用and
操作符,用来连接其他子进程;当子进程的返回状态码为0 proc.returncode == 0
时,结果为True;
>>> touch exists
>>> ls exists and ls doesnt
exists
/bin/ls: cannot access doesnt: No such file or directory
但是如果左侧子进程输出为False时,右侧则不会被执行;
>>> ls doesnt and ls exists
/bin/ls: cannot access doesnt: No such file or directory
xonsh直接将&&
转换成了and
使用,如何使用取决你。
Logical subprocess or 逻辑子进程or
与and
操作符相同,or
操作符也可以用来连接其他子进程,但不同的是,只有子进程的返回状态码非0时,程序才会接着被执行;
>>> # 由于文件exists已经存在,程序不会执行or之后的
>>> ls exists or ls doesnt
exists
但是如果左侧子进程状态码不为0,右侧程序才会被执行;
>>> ls doesnt or ls exists
/bin/ls: cannot access doesnt: No such file or directory
exists
xonsh同样也将||
转换成了or
,放心使用。
Input/Output rediretion 输入输出重定向
xonsh允许重定向stdin
、stdout
、stderr
,并且设计了各自的操作符,但考虑到兼容性,xonsh也支持bash-like的操作符。
xonsh基础的操作符:写入>
、追加>>
、读取<
,这些操作符均应该使用空格隔开,否则会引起
Syntax Error
;下方的例子执行COMMAND
,并且将输出写入至文件中(不存在将被新建)
-
重定向
stdout
>>> COMMAND > output.txt >>> COMMAND out> output.txt >>> COMMAND o> output.txt >>> COMMAND 1> output.txt # included for Bash compatibility
-
重定向
stdrr
>>> COMMAND err> errors.txt >>> COMMAND e> errors.txt >>> COMMAND 2> errors.txt # included for Bash compatibility
-
连接streams
也可以输出:标准输出+标准错误
>>> COMMAND all> combined.txt >>> COMMAND a> combined.txt >>> COMMAND &> combined.txt # included for Bash compatibility # 或者显示将标准错误输出至标准输出 >>> COMMAND err>out >>> COMMAND err>o >>> COMMAND e>out >>> COMMAND e>o >>> COMMAND 2>&1 # included for Bash compatibility # 将上述方式结合 >>> COMMAND err>out | COMMAND2 >>> # 与 COMMAND a> combined.txt 相同 >>> COMMAND e>o > combined.txt
-
重定向
stdin
从文件中读取
>>> COMMAND < input.txt >>> < input.txt COMMAND
从标准输入读取,并且可组合在一起使用:
>>> # command1读取input.txt,并且把标准错误输出至标准输出,然后作为管道输出至command2中,标准输出写入至output.txt,标准错误写入至errors.txt >>> COMMAND1 e>o < input.txt | COMMAND2 > output.txt e>> errors.txt
Background jobs 后台运行
一般在子进程模式下运行代码,xonsh会暂停并等待程序运行结束;当希望子进程在后台运行时,可以在代码之后添加&
。
Job control 任务控制
如果子进程在前台运行时,可以按下Ctrl+Z
暂停程序运行,并且返回xonsh界面(但该模式在windows中不支持);
使用fg
可恢复之前暂停的程序;如果不暂停程序并在后台运行时,可使用bg
命令;
使用jobs
命令可查看当前正在运行的jobs;每个job都有唯一的识别符,从1开始;默认的情况下,fg
和bg
命令操作的是最近启动的job;可以在fg
和bg
命令后添加特定的识别符,来操作先前的job,例如fg 1
把标识符为1的job调至前台运行;
除此之外,指定+
可匹配最近的工作,-
可匹配第二个最近的工作。