XONSH简明教程 Part1

Xonsh简明教程

  • 翻译文档地址: https://xon.sh/tutorial.html
  • 非严谨翻译,仅作记录参考

Starting xonsh 开始使用

安装好xonsh之后,输入xonsh即可,

Basic 基础用法

xonsh基于python语言,因此也可使用python解释器执行,基本功能与pythonshell相同

Environment variables 环境变量

使用$来定义环境变量,如$HOME,但在更新os.environ时,需要设置$UPDATE_OS_ENVIRONEMNTtrue

>>> $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访问时,也有存在类型,如listintdict

  • \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允许重定向stdinstdoutstderr,并且设计了各自的操作符,但考虑到兼容性,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开始;默认的情况下,fgbg命令操作的是最近启动的job;可以在fgbg命令后添加特定的识别符,来操作先前的job,例如fg 1把标识符为1的job调至前台运行;

除此之外,指定+可匹配最近的工作,-可匹配第二个最近的工作。

你可能感兴趣的:(XONSH简明教程 Part1)