<p align="center">
Cheat sheet for the <a href="https://xon.sh">xonsh shell</a> with copy-pastable examples. This is a good level of knowledge to start being productive.
<br><br>
<img src="https://repository-images.githubusercontent.com/310804308/f11fa180-280d-11eb-8fa4-c389308692bd">
</p>
<p align="center">
If you like the cheatsheet click ⭐ on the repo and <a href="https://twitter.com/intent/tweet?text=The%20xonsh%20shell%20cheat%20sheet.&url=https://github.com/anki-code/xonsh-cheatsheet" target="_blank">tweet</a> about it.
</p>
[Full screen reading](https://github.com/anki-code/xonsh-cheatsheet/blob/main/README.md)
# What is xonsh?
Xonsh is a Python-powered, cross-platform, Unix-gazing shell language and command prompt. The language is a superset of Python 3.6+ with additional shell primitives that you are used to from [Bash](https://www.gnu.org/software/bash/) and [IPython](https://ipython.org/). It works on all Python-compatible systems, including Linux, macOS, and Windows. Try [right off the bat examples](https://github.com/anki-code/xonsh-cheatsheet/blob/main/README.md#xonsh-basics).
# What does xonsh mean?
The "xonsh" word sounds like [conch [kɑːntʃ]](https://www.google.com/search?q=what+is+conch) - a common name of a number of different sea snails or shells (🐚). Thus xonsh is the reference to the shell word that is commonly used to name [command shells](https://en.wikipedia.org/wiki/Shell_(computing)).
You will also face with "xontrib" word. The xontrib is short version of ["(contrib)ution"](https://www.collinsdictionary.com/dictionary/english/contribution) word and points to extensions, community articles and other materials around xonsh.
# Install xonsh
There are three ways to use xonsh:
1. **[Simple xonsh install](#simple-xonsh-install)**. You can use the system installed Python to install xonsh and dependencies. This is a good option if you don't plan to manage Python versions or virtual environments.
2. **[Install xonsh with package and environment management system](#install-xonsh-with-package-and-environment-management-system)**. In this way you can flexibly manage the Python version, dependencies, and virtual environments, but because xonsh is a Python-based shell you have to understand what you're doing and the section below will provide some guidance.
3. **[Try xonsh without installation](#try-xonsh-without-installation)**. Use Docker or the Linux AppImage to run and try xonsh.
### Simple xonsh install
Most modern operating systems have [Python](https://www.python.org/) and [PyPi (pip)](https://packaging.python.org/tutorials/installing-packages/) that are preinstalled or that can be installed easily. By installing from PyPi you will get [the latest version of the xonsh shell](https://github.com/xonsh/xonsh/releases). We highly recommend using the `full` version of the xonsh PyPi-package with [prompt-toolkit](https://python-prompt-toolkit.readthedocs.io/en/master/) on board:
```xsh
python -m pip install 'xonsh[full]'
```
Another way is to install xonsh from the package manager that is supplied by the operating system. This way is _not_ recommended in operating systems without the [rolling release concept](https://en.wikipedia.org/wiki/Rolling_release) the xonsh shell version may be very old ([check latest xonsh release](https://github.com/xonsh/xonsh/releases/) or [versions of xonsh across platforms](https://repology.org/project/xonsh/versions)) because the average [release cycle for the xonsh shell](https://github.com/xonsh/xonsh/releases) is quarter.
```xsh
# Not recommended but possible
apt install xonsh # Debian/Ubuntu
dnf install xonsh # Fedora
brew install xonsh # OSX
```
Arch Linux *is* a rolling release system, so you are fine using that:
```xsh
pacman -S xonsh python-prompt_toolkit # Arch Linux
```
On any system you can install `python` and then install xonsh from pip i.e., `any_pkg_manager install python && python -m pip install 'xonsh[full]'` This is the preferable way.
### Install xonsh with package and environment management system
Xonsh is a Python-based shell, and to run xonsh you must have Python installed. The Python version and its packages can be installed and located anywhere: in the operating system directories, as part of a virtual environment, as part of the user directory, or as a virtual drive created temporarily behind the scenes by the Linux AppImage.
The first thing you have to remember is that when you execute `import` or any other Python code during a xonsh session it will be executed in the Python environment that was used to run current instance of xonsh. Use the [xc alias](https://github.com/anki-code/xontrib-rc-awesome/blob/c643e4cbc5cdb88c72a0389c03c62fd5407363d2/xontrib/rc_awesome.xsh#L87) to check the xonsh context.
In other words, you can activate a virtual environment during a xonsh session (using conda, pyenv, pipx) but the current session will continue to use packages from the environment that was used to run xonsh. And if you want to run xonsh with the packages from the currently activated virtual environment you have to install xonsh in that environment and run it directly.
Thus the second thing you should remember is that when you run xonsh in virtual environment it will try to load [xonsh RC files](https://xon.sh/xonshrc.html#run-control-file) (i.e. `~/.xonshrc`) and because the virtual environment is different from the environement you ordinarily use, the loading of the RC file will tend to fail because of the lack of the appropriate set of packages. When you write your `~/.xonshrc` it's good practice to check the existing external dependencies before loading them. See also [xontrib-rc-awesome](https://github.com/anki-code/xontrib-rc-awesome).
#### Install xonsh on macOS or Linux using conda
You can use [Conda](https://docs.conda.io/en/latest/) with [Conda-forge](https://conda-forge.org/) to install and use xonsh.
```xsh
#
# Install python using brew
#
zsh # Default macOS shell
# Install brew from https://brew.sh/
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install python # or `python@3.11`
#
# Install Miniconda from https://docs.conda.io/en/latest/miniconda.html
# (example for Mac, use the link for your platform)
#
cd /tmp
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh
chmod +x Miniconda3-latest-MacOSX-arm64.sh
./Miniconda3-latest-MacOSX-arm64.sh
# Add conda init code that was printed to `~/.zshrc` and restart zsh.
# Or run `/Users/username/miniconda3/bin/conda init zsh` to add init to ~/.zshrc and restart zsh.
# After restarting zsh you will see `(base)` in prompt.
# This means that you're in the conda `base` environment.
# Switch to Conda-forge channel
conda config --add channels conda-forge
conda config --set channel_priority strict
conda update --all --yes
# Install xonsh to the `base` environment
conda install xonsh
conda init xonsh # Add init to ~/.xonshrc. You can also add `$CONDA_AUTO_ACTIVATE_BASE='false'` to avoid conda loading at start
which xonsh
# /Users/username/miniconda3/bin/xonsh
# Run xonsh from the `base` environment
xonsh
```
How to work and understand the environments in conda:
```xsh
# `xpip` is used to install packages to the current xonsh session location (now it's `base` environment)
xpip install ujson
# Example of creating the environment with a certain version of Python
conda search python | grep 3.10
conda create -n "py310" python=3.10 xonsh
conda activate py310
# Now the environment is `py310` but current xonsh session is still in `base` environment
which xonsh
# /Users/username/miniconda3/envs/py310/bin/xonsh
which pip
# /Users/username/miniconda3/envs/py310/bin/pip # pip from `py310`
which xpip
# /Users/username/miniconda3/bin/pip # pip from `base` environment from where xonsh ran
# Run xonsh that installed in `py310` environment from xonsh runned in `base` environment
xonsh
conda activate py310
# Now xonsh session is in `py310` environment and the current environment is also `py310`
import ujson
# No module named 'ujson' # YES because ujson was installed in `base` environment
```
On Mac we also recommend to install [GNU coreutils](https://www.gnu.org/software/coreutils/) to use the Linux default tools (i.e. `ls`, `grep`):
```xsh
brew install coreutils
$PATH.append('/opt/homebrew/opt/coreutils/libexec/gnubin') # add to ~/.xonshrc
```
#### How to understand the xonsh location
Which xonsh and which Python used to run the **current** xonsh session:
```xsh
import sys
[sys.argv[0], sys.executable]
# ['/opt/homebrew/bin/xonsh', '/opt/homebrew/opt/python@3.11/bin/python3.11']
@(sys.executable) -m site
# Full info about paths
```
Which `xonsh` and which `python` that will be executed to run **new instances** depends on the list of directories in `$PATH` or virtual environment:
```xsh
$PATH
# ['/home/user/miniconda3/bin', '/opt/homebrew/bin]
[$(ls -la @$(which xonsh)), $(ls -la @$(which python)), $(python -V)]
# ['/home/user/miniconda3/bin/xonsh', '/home/user/miniconda3/bin/python -> python3.11', 'Python 3.11.1']
python -m site
# Full info about paths
```
#### pipx and xonsh
The [pipx](https://pipxproject.github.io/pipx/) tool is also good to install xonsh in case you need certain Python version:
```xsh
# Install Python before continuing
pip install pipx
pipx install --python python3.8 xonsh # Here `python3.8` is the path to installed python.
pipx run xonsh
# or add /home/$USER/.local/bin to PATH (/etc/shells) to allow running just the `xonsh` command
```
### Try xonsh without installation
#### Docker
```python
# Docker with specific Python version and latest release of xonsh
docker run --rm -it python:3.11-slim /bin/bash \
-c "pip install 'xonsh[full]' && xonsh"
# Docker with specific Python version and xonsh from the master branch
docker run --rm -it python:3.11-slim /bin/bash \
-c "apt update && apt install -y git && pip install -U git+https://github.com/xonsh/xonsh && xonsh"
# Official xonsh docker image may has an old version
docker run --rm -it xonsh/xonsh:slim
```
#### Linux-portable AppImage contains both [Python 3 and xonsh in one file](https://xon.sh/appimage.html)
```python
wget https://github.com/xonsh/xonsh/releases/latest/download/xonsh-x86_64.AppImage -O xonsh
chmod +x xonsh
./xonsh
# Then if you don’t have Python on your host, you can acccess it from the AppImage by running:
$PATH = [$APPDIR + '/usr/bin'] + $PATH
python -m pip install tqdm --user # the `tqdm` package will be installed to ~/.local/
import tqdm
```
You can [build your own xonsh AppImage](https://xon.sh/appimage.html#building-your-own-xonsh-appimage) with the packages you need in 15 minutes.
# Xonsh basics
The xonsh language is a superset of Python 3 with additional shell support. As result you can mix shell commands and Python code as easily as possible. Right off the bat examples:
```xsh
cd /tmp && ls # shell commands
21 + 21 # python command
for i in range(0, 42): # mix python
echo @(i+1) # and the shell
len($(curl https://xon.sh)) # mix python and the shell
$PATH.append('/tmp') # using environment variables
p'/etc/passwd'.read_text().find('root') # path-string returns Path
# (https://docs.python.org/3/library/pathlib.html)
for line in $(cat /etc/passwd).splitlines(): # read the lines from the output
echo @(line.split(':')[0]) # prepare line on Python and echo
for file in gp`*.*`: # reading the list of files as Path-objects
if file.exists(): # using rich functionality of Path-objects
du -sh @(file) # and pass it to the shell command
import json # python libraries are always at hand
if docker_info := $(docker info --format '{{json .}}'):
print('ContainersRunning:', json.loads(docker_info)['ContainersRunning'])
xpip install xontrib-prompt-bar # xonsh has huge amount of powerful extensions
xontrib load prompt_bar # follow the white rabbit - https://github.com/topics/xontrib
# Finally fork https://github.com/anki-code/xontrib-rc-awesome
# to convert your ~/.xonshrc into a pip-installable package
# with the extensions you need on board.
```
Looks nice? [Install xonsh](#install-xonsh)!
## Three most frequent things that newcomers overlook
### 1. [Shell commands, also known as subprocess commands](https://xon.sh/tutorial.html#python-mode-vs-subprocess-mode)
The first thing you should remember is that the shell commands are not the calls of another shell (i.e. bash). Xonsh has its own parser implementation for subprocess commands, and this is why a command like `echo {1..5} \;` (brace expansion and escape characters in bash) won't work. Most sh-shell features [can be replaced](https://xon.sh/bash_to_xsh.html) by sane Python alternatives. For example, the earlier command could be expressed as `echo @(range(1,6)) ';'`.
If you think that only xonsh has the sh-uncompatible elements in its parser, you are mistaken. If we compare Bash and Zsh we will find that `pip install package[subpackage]` command will work in Bash but in Zsh the error will be raised because Zsh has a special meaning for square braces. It's normal to have an evolution in the syntax and features.
Be calm and accept the sane and self-consistent Python-driven mindset.
*Note:*
* *Most of novice try to copy and paste sh-lang commands that contain special characters and get syntax errors in xonsh. If you want to run environment agnostic sh-lang's commands that you copy from the internet just use the macro call in xonsh `bash -c! echo {123}` or use [xontrib-sh](https://github.com/anki-code/xontrib-sh) to run context-free bash commands in xonsh by adding `! ` at the beginning of the command.*
* *We highly recommend to taking a look at the section [Install xonsh with package and environment management system](#install-xonsh-with-package-and-environment-management-system).*
### 2. [Strings and arguments in shell commands](https://xon.sh/tutorial_subproc_strings.html)
The second potential misunderstanding comes from the first. To escape special charecters, the special meaning of braces, or pass a string as an argument, use quotes. When in doubt, use quotes!
You should clearly understand the difference:
<table style="width:100%">
<tr>
<th>sh-lang shells</th>
<th>xonsh</th>
</tr>
<tr>
<td>
1. Has an escape character:
<pre>
<b>echo 123\ 456</b>
# 123 456
</pre>
</td>
<td>
1. Use quotes:
<pre>
<b>echo "123 456"</b>
# 123 456
</pre>
<a href="https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals">Escape character</a> to wrap and so on:
<pre>
<b>echo "123\
456"</b>
# 123456
</pre>
</td>
</tr>
<tr>
<td>
2. Open the quotes:
<pre>
<b>echo --arg="val"</b>
# --arg=val<br>
# and:<br>
<b>echo --arg "val"</b>
# --arg val
</pre>
</td>
<td>
2. Save quotes:
<pre>
<b>echo --arg="val"</b>
# --arg="val"<br>
# But if argument quoted entirely:<br>
<b>echo --arg "val"</b>
# --arg val
</pre>
</td>
</tr>
<tr>
<td>
3. Brackets have no meaning:
<pre>
<b>echo {123} [456]</b>
# {123} [456]<br><br><br>
</pre>
</td>
<td>
3. Brackets have meaning:
<pre>
<b>echo {123} [456]</b>
# SyntaxError<br>
<b>echo "{123}" '[456]'</b>
# {123} [456]
</pre>
</td>
</tr>
</table>
*Note:*
* *You can wrap any argument into Python string substitution:*
```python
name = 'snail'
echo @('--name=' + name.upper())
# --name=SNAIL
```
* *You can use the `showcmd` command to show the arguments list:*
```python
showcmd echo The @('arguments') @(['list', 'is']) $(echo here) "and" --say="hello" to you
# ['echo', 'The', 'arguments', 'list', 'is', 'here\n', 'and', '--say="hello"', 'to', 'you']]
```
### 3. The process substitution operator `$()` returns output with [universal new lines](https://www.python.org/dev/peps/pep-0278/)
In sh-compatible shells, the [process substitution operator](https://en.wikipedia.org/wiki/Process_substitution) `$()` executes the command and then splits the output and uses those parts as arguments. The command `echo $(echo -e "1 2\n3")` will have three distinct arguments, `1`, `2` and `3` that will passed to the first `echo`.
In xonsh shell the `$()` operator returns the output of the command. The command `echo $(echo -e "1 2\n3")` will have one argument, `1 2\n3\n` that will be passed to the first `echo`.
*Note:*
* *To do what sh-compatible shells are doing with the `$()` operator, the xonsh shell has the `@$()` operator that will be described in the next chapter.*
```python
showcmd echo @$(echo "1\n2 3\n4")
# ['echo', '1', '2', '3', '4']
```
* *To transform output to the lines for the arguments list you can use [splitlines](https://docs.python.org/3/library/stdtypes.html#str.splitlines) function and the python substitution:*
```python
showcmd echo @($(echo "1\n2 3\n4").splitlines()) # the first echo will get three arguments: "1", "2 3", "4"
# ['echo', '1', '2 3', '4']
```
* *Not all xonsh users like this behavior of `$()` operator, and in the future, this may be changed. There is [a thread to discussing](https://github.com/xonsh/xonsh/issues/3924) this and the [Xonsh Enhancement Proposal #2](https://github.com/anki-code/xonsh-operators-proposal/blob/main/XEP-2.rst).*
# [Operators](https://xon.sh/tutorial.html#captured-subprocess-with-and)
### `$()` - capture and return output without printing stdout and stderr
Captures stdout and returns output with [universal new lines](https://www.python.org/dev/peps/pep-0278/):
```python
showcmd $(echo -e '1\n2\r3 4\r\n5') # Subproc mode
# ['1\n2\n3 4\n5\n']
output = $(echo -e '1\n2\r3 4\r\n5') # Python mode
output
# '1\n2\n3 4\n5\n'
```
### `!()` - capture all and return object without printing stdout and stderr
Captures stdout and returns [CommandPipeline](https://xon.sh/api/procs/pipelines.html#xonsh.procs.pipelines.CommandPipeline). Truthy if successful (returncode == 0), compares to, iterates over lines of stdout:
```python
ret = !(echo 123)
ret
#CommandPipeline(
# pid=404136,
# returncode=0,
# args=['echo', '123'],
# alias=None,
# timestamps=[1604742882.1826484, 1604742885.1393967],
# executed_cmd=['echo', '123'],
# input='',
# output='123\n',
# errors=None
#)
if ret:
print('Success')
#Success
for l in ret:
print(l)
#123
#
```
Note! In some cases, to get the output you need to convert an object to a string or invoke [`.end()`](https://github.com/xonsh/xonsh/blob/6d58fb5bf7c62fa5c56721b62f40b214f83822eb/xonsh/procs/pipelines.py#L450-L459) manually or use the `.out`:
```xsh
r = !(ls /)
r.output
# ''
r.end()
r.output
# 'bin\netc\n...'
r = !(ls /)
r.out # out is forcing ending
# 'bin\netc\n...'
r = !(ls /)
print(r) # r will be converted to str and the ending will be forced
# bin
# etc
# ...
```
### `$[]` - not capturing (return `None`), print stdout and stderr
Passes stdout to the screen and returns `None`:
```python
ret = $[echo 123]
# 123
repr(ret)
# 'None'
```
This is the same as `echo 123`, but this syntax allows explicitly running a subprocess command.
### `![]` - capture all and return hidden object, print stdout and stderr
*Note! The behavior may be different if [`$XONSH_CAPTURE_ALWAYS`](https://xon.sh/envvars.html#xonsh-capture-always) is True or False (default).*
Passes stdout to the screen and returns [HiddenCommandPipeline](https://xon.sh/api/procs/pipelines.html#xonsh.procs.pipelines.HiddenCommandPipeline):
```python
with __xonsh__.env.swap(XONSH_CAPTURE_ALWAYS=True):
ret = ![echo -e '1\n2\r3 4\r\n5']
# 1 # Stream output of the command
# 3 4
# 5
ret # No return value because it's HiddenCommandPipeline object
ret.out # But it has the properties from CommandPipeline
# '1\n2\r3 4\n5\n'
```
This operator is used under the hood for running commands at the interactive xonsh prompt.
### `@()` - use Python code as an argument or a callable alias
Evaluates Python and passes the arguments:
```python
showcmd 'Supported:' @('string') @(['list','of','strings'])
#['Supported:', 'string', 'list', 'of', 'strings']
echo -n '!' | @(lambda args, stdin: 'Callable' + stdin.read())
#Callable!
```
### `@$()` - split output of the command by white spaces for arguments list
```python
showcmd @$(echo -e '1\n2\r3 4\r\n5')
#['1', '2\r3', '4', '5']
```
This is mostly [what bash's `$()` operator does](https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html).
# [Environment Variables](https://xon.sh/tutorial.html#environment-variables)
```python
${...} # Get the list of environment variables
__xonsh__.env # Get the list of environment variables using Python syntax
$VAR = 'value' # Set environment variable
ENV = ${...} # short typing
ENV.get('VAR', 'novalue') # the good practice to have a fallback for missing value
# 'value'
ENV.get('VAR2', 'novalue') # the good practice to have a fallback for missing value
# 'novalue'
'VAR' in ${...} # Check environment variable exists
#True
${'V' + 'AR'} # Get environment variable value by name from expression
#'value'
print($VAR)
with ${...}.swap(VAR='another value', NEW_VAR='new value'): # Change VAR for commands block
print($VAR)
print($VAR)
#value
#another value
#value
$VAR='new value' xonsh -c r'echo $VAR' # Change variable for subprocess command
#new value
__xonsh__.env.get('VAR', 'novalue') # the way to call environment using the __xonsh__ builtin
# 'value'
```
Python and subprocess mode:
```python
print("my home is $HOME") # Python mode
# my home is $HOME
print("my home is " + $HOME) # Python mode
# my home is /home/snail
echo "my home is $HOME" as well as '$HOME' # Subprocess mode
# my home is /home/snail as well as /home/snail
```
Work with [`$PATH`](https://xon.sh/envvars.html#path):
```python
$PATH
# EnvPath(
# ['/usr/bin',
# '/sbin',
# '/bin']
# )
$PATH.add(p"~/bin", front=True, replace=True)) # Insert path '~/bin' at front of $PATH list and replace existing entries
$PATH.add(p"~/bin", front=True) # Insert path '~/bin' at front of $PATH list
$PATH.add(p"~/bin", front=False, replace=True)) # Insert path '~/bin' at end of $PATH list and replace existing entries
$PATH.insert(0, '/tmp') # Insert path '/tmp' at front of $PATH list
$PATH.append('/tmp') # Append path '/tmp' at end of $PATH list
$PATH.remove('/tmp') # Remove path '/tmp' (first match)
```
Setup local paths by prepending to path via a loop in `.xonshrc`:
```python
import os.path
from os import path
$user_bins = [
f'{$HOME}/.cargo/bin',
f'{$HOME}/.pyenv/bin',
f'{$HOME}/.poetry/bin',
f'{$HOME}/bin',
f'{$HOME}/local/bin',
f'{$HOME}/.local/bin',
]
for dir in $user_bins:
if path.isdir(dir) and path.exists(dir):
$PATH.add(dir,front=True, replace=True)
```
See also the list of [xonsh default environment variables](http://xon.sh/envvars.html).
# [Aliases](https://xon.sh/tutorial.html#aliases)
## Simple aliases
```python
aliases['g'] = 'git status -sb' # Add alias as string
aliases['e'] = 'echo @(2+2)' # Add xonsh executable alias (ExecAlias)
aliases['gp'] = ['git', 'pull'] # Add alias as list of arguments
aliases['b'] = lambda: "Banana!\n" # Add alias as simple callable lambda
aliases |= {'a': 'echo a', 'b':'echo b'} # Add aliases from the dict
del aliases['b'] # Delete alias
```
Easy wrapping a command by using [ExecAlias](https://xon.sh/tutorial.html#aliases) with built-in [`$args`](https://xon.sh/tutorial.html#aliases) (or `$arg0`, `$arg1`, etc) variable:
```python
aliases['echo-new'] = "echo @($args) new"
$(echo-new hello)
# 'hello new\n'
$(echo-new -n hello)
# 'hello new'
```
Also with handy `"""`-string to use `"` and `'` without escaping:
```python
aliases['scmd'] = """showcmd @([a for a in $args if a != "cutme"])"""
scmd
# usage: showcmd [-h|--help|cmd args]
# Displays the command and arguments as a list ...
scmd 1 2 cutme 3
#['1', '2', '3']
```
## [Callable aliases](https://xon.sh/tutorial.html#callable-aliases)
```python
def _myargs1(args):
#def _myargs2(args, stdin=None):
#def _myargs3(args, stdin=None, stdout=None):
#def _myargs4(args, stdin=None, stdout=None, stderr=None):
#def _myargs5(args, stdin=None, stdout=None, stderr=None, spec=None):
#def _myargs6(args, stdin=None, stdout=None, stderr=None, spec=None, stack=None):
print(args)
aliases['args'] = _myargs1
del _myargs1
args 1 2 3
#['1', '2', '3']
```
Simple definition with [decorator](https://wiki.python.org/moin/PythonDecorators#What_is_a_Python_Decorator):
```xsh
@aliases.register("hello")
def __hello():
echo world
hello
# world
```
Read stdin and write to stdout (real-life example - [xontrib-pipeliner](https://github.com/anki-code/xontrib-pipeliner)):
```xsh
# Add an exclamation point to each line
def _exc(args, stdin, stdout):
for line in stdin.readlines():
print(line.strip() + '!', file=stdout, flush=True)
aliases['exc'] = _exc
echo hello | exc
# hello!
```
```xsh
# JSON to YAML
@aliases.register("j2y")
def __j2y(args, stdin, stdout):
import json, yaml
print(yaml.dump(json.loads(stdin.read())), file=stdout)
# YAML to JSON
@aliases.register("y2j")
def __y2j(args, stdin, stdout):
import yaml, json
json.dump(yaml.safe_load(stdin), stdout, indent=4)
echo '{"hello":{"world":"42"}}' | j2y
# hello:
# world: 42
echo 'hello:\n world: 42' | y2j
# {
# "hello": {
# "world": "42"
# }
# }
```
## Abbrevs
There is [xontrib-abbrevs](https://github.com/xonsh/xontrib-abbrevs) as alternative to aliases. You can create abbrev and set the position of editing:
```xsh
xpip install xontrib-abbrevs
xontrib load abbrevs
abbrevs['gst'] = 'git status'
gst # Once you hit <space> or <return> 'gst' gets expanded to 'git status'.
abbrevs['gp'] = "git push <edit> --force" # Set the edit position.
abbrevs['@'] = "@(<edit>)" # Make shortcut.
abbrevs['...'] = "cd ../.." # Workaround for syntax intersections with Python i.e. `elepsis` object from Python here.
# You can set a callback that receives current command buffer and word that triggered abbrev
abbrevs['*'] = lambda buffer, word: "asterisk" if buffer.text.startswith('echo') else word
ls * # will stay
echo * # will be transformed to `echo asterisk`
```
# [Path strings](https://xon.sh/tutorial.html#advanced-string-literals)
The p-string returns [Path object](https://docs.python.org/3/library/pathlib.html):
```python
path = p'~/.xonshrc'
path
# Path('/home/snail/.xonshrc')
[path.name, path.exists(), path.parent]
# ['.xonshrc', True, Path('/home/snail')]
[f for f in path.parent.glob('*') if 'xonsh' in f.name]
# [Path('/home/snail/.xonshrc')]
dir1 = 'hello'
dir2 = 'world'
path = p'/tmp' / dir1 / dir2 / 'from/dir' / f'{dir1}'
path
# Path('/tmp/hello/world/from/dir/hello')
```
A simple way to read and write the file content using Path string:
```python
text_len = p'/tmp/hello'.write_text('Hello world')
content = p'/tmp/hello'.read_text()
content
# 'Hello world'
```
# [Globbing](https://xon.sh/tutorial.html#normal-globbing) - get the list of files from path by mask or regexp
To [Normal globbing](https://xon.sh/tutorial.html#normal-globbing) add `g` before back quotes:
```python
ls *.*
ls g`*.*`
for f in gp`/tmp/*.*`: # `p` is to return path objects
print(f.name)
for f in gp`/tmp/*/**`: # `**` is to glob subdirectories
print(f)
```
To [Regular Expression Globbing](https://xon.sh/tutorial.html#regular-expression-globbing) add `r` before back quotes:
```python
ls `.*`
ls r`.*`
for f in rp`.*`: # `p` is to return path instances
print(f.exists())
```
To [Custom function globbing](https://xon.sh/tutorial.html#custom-path-searches) add `@` and the function name before back quotes:
```python
def foo(s):
return [i for i in os.listdir('.') if i.startswith(s)]
cd /
@foo`bi`
#['bin']
```
# Macros
## [Simple macros](https://xon.sh/tutorial_macros.html#function-macros)
```python
def m(x : str):
return x
# No macro calls:
[m('me'), m(42), m(m)]
# ['me', 42, <function __main__.m>]
# Macro calls:
[m!('me'), m!(42), m!(identity), m!(42), m!( 42 ), m!(import os)]
# ["'me'", '42', 'identity', '42', '42', 'import os']
m!(if True:
pass)
# 'if True:\n pass'
```
## [Subprocess Macros](https://xon.sh/tutorial_macros.html#subprocess-macros)
```python
echo! "Hello!"
# "Hello!"
bash -c! echo "Hello!"
# Hello!
docker run -it --rm xonsh/xonsh:slim xonsh -c! 2+2
# 4
```
Inside of a macro, all [additional munging](https://xon.sh/tutorial.html#string-literals-in-subprocess-mode) is turned off:
```python
echo $USER
# lou
echo! $USER
# $USER
```
## [Macro block](https://xon.sh/tutorial_macros.html#context-manager-macros)
### Builtin macro Block
```python
from xonsh.contexts import Block
with! Block() as b:
qwe
asd
zxc
b.macro_block
# 'qwe\nasd\nzxc\n\n'
b.lines
# ['qwe', 'asd', 'zxc', '']
```
### Custom JSON block
```python
import json
class JsonBlock:
__xonsh_block__ = str
def __enter__(self):
return json.loads(self.macro_block)
def __exit__(self, *exc):
del self.macro_block, self.macro_globals, self.macro_locals
with! JsonBlock() as j:
{
"Hello": "world!"
}
j['Hello']
# world!
```
### Custom Docker block
The example is from [xontrib-macro-lib](https://github.com/anki-code/xontrib-macro-lib):
```python
from xonsh.contexts import Block
class Doxer(Block):
"""Run xonsh codeblock in docker container."""
def __init__(self):
self.docker_image = 'xonsh/xonsh:slim'
def __exit__(self, *a, **kw):
$[docker run -it --rm @(self.docker_image) /usr/local/bin/xonsh -c @(self.macro_block)]
with! Doxer() as d:
pip install lolcat
echo "We're in docker container now!" | lolcat
```
### Macro blocks library
See also [xontrib-macro-lib](https://github.com/anki-code/xontrib-macro-lib).
# [Tab-Completion](https://xon.sh/tutorial_completers.html)
```python
completer list # List the active completers
```
Take a look into [xontrib-fish-completer](https://github.com/xonsh/xontrib-fish-completer) - it provides more rich completion than default bash completer.
Create your own completer:
```
def dummy_completer(prefix, line, begidx, endidx, ctx):
'''
Completes everything with options "lou" and "carcolh",
regardless of the value of prefix.
'''
return {"lou", "carcolh"}
completer add dummy dummy_completer # Add completer: `completer add <NAME> <FUNC>`
# Now press Tab key and you'll get {"lou", "carcolh"} in completions
completer remove dummy
```
# Bind hotkeys in prompt toolkit shell
Uncover the power of [prompt_toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit#python-prompt-toolkit) by [binding](https://xon.sh/tutorial_ptk.html) the [hotkeys](https://github.com/prompt-toolkit/python-prompt-toolkit/blob/master/src/prompt_toolkit/keys.py). Run this snippet or add it to `~/.xonshrc`:
```python
from prompt_toolkit.keys import Keys
@events.on_ptk_create
def custom_keybindings(bindings, **kw):
# Press F1 and get the list of files
@bindings.add(Keys.F1) # or for Mac try `@bindings.add("c-k") # control+k`
def run_ls(event):
ls -l
event.cli.renderer.erase()
# Press F3 to insert the grep command
@bindings.add(Keys.F3) # or for Mac try `@bindings.add("c-k") # control+k`
def add_grep(event):
event.current_buffer.insert_text('| grep -i ')
# Clear line by pressing `Escape` key
@bindings.add("escape")
def clear_line(event):
event.current_buffer.delete_before_cursor(1000)
```
See also: [more about key bindings](https://python-prompt-toolkit.readthedocs.io/en/master/pages/advanced_topics/key_bindings.html), [event.current_buffer](https://python-prompt-toolkit.readthedocs.io/en/stable/pages/reference.html#prompt_toolkit.buffer.Buffer).
# [Xontrib](https://xon.sh/tutorial_xontrib.html) - extension or plugin for xonsh
Xontrib lists:
* [Github topic](https://github.com/topics/xontrib)
* [Github repositories](https://github.com/search?q=xontrib-&type=repositories)
* [awesome-xontribs](https://github.com/xonsh/awesome-xontribs)
To install xontribs xonsh has [`xpip`](https://xon.sh/aliases.html?highlight=aliases#xpip) - a predefined alias pointing to the pip command associated with the Python executable running this xonsh. Using `xpip` is the right way to install xontrib to be confident that the xontrib will be installed in the right environment.
If you want to create your own xontrib [using xontrib-template](https://github.com/xonsh/xontrib-template) is the best way:
```python
xpip install copier jinja2-time cookiecutter
copier gh:xonsh/xontrib-template .
```
# Xonsh Script (xsh)
Real-life example of xsh script that has: arguments, tab completion for arguments (using [xontrib-argcomplete](https://github.com/anki-code/xontrib-argcomplete)), subprocess calls with checking the result, colorizing the result and exit code:
```python
#!/usr/bin/env xonsh
# PYTHON_ARGCOMPLETE_OK
import argparse
import argcomplete # Tab completion support with xontrib-argcomplete
from argcomplete.completers import ChoicesCompleter
$RAISE_SUBPROC_ERROR = True # Raise an error if a subprocess returns a non-zero exit status.
# Read more: https://xon.sh/envvars.html#raise-subproc-error
argp = argparse.ArgumentParser(description=f"Get count of lines in HTML by site address.")
argp.add_argument('--host', required=True, help="Host").completer=ChoicesCompleter(('xon.sh', 'github.com'))
argcomplete.autocomplete(argp)
args = argp.parse_args()
if result := !(curl -s -L @(args.host)): # Python + Subprocess = ♥
lines_count = len(result.out.splitlines())
printx(f'{{GREEN}}Count of lines on {{#00FF00}}{args.host}{{GREEN}}: {{YELLOW}}{lines_count}{{RESET}}')
else:
printx(f'{{RED}}Error while reading {{YELLOW}}{args.host}{{RED}}! {{RESET}}') # Colorizing messages
exit(1) # Exit with code number 1
```
Try it in action:
```python
xonsh
pip install argcomplete xontrib-argcomplete
xontrib load argcomplete
cd /tmp
wget https://raw.githubusercontent.com/anki-code/xonsh-cheatsheet/main/examples/host_lines.xsh
chmod +x host_lines.xsh
./host_lines.xsh --ho<Tab>
./host_lines.xsh --host <Tab>
./host_lines.xsh --host xon.sh
# Count of lines on xon.sh: 568
```
To make the interaction with script more awesome [use `click`, `typer` and `rich`](https://betterprogramming.pub/designing-beautiful-command-line-applications-with-python-72bd2f972ea):
```xsh
"""Example of CLI application."""
import click
class OrderCommands(click.Group):
def list_commands(self, ctx: click.Context) -> list[str]:
return list(self.commands)
class CliCtx:
"""CLI application sharable context."""
def __init__(self, debug):
self.debug = debug
if self.debug:
# Show arguments in debug mode.
from pprint import pprint
pprint(vars(self))
@click.group(cls=OrderCommands) # The list of commands in `--help` will be the same as the functions declarations order.
@click.option("--debug", default=False, is_flag=True, envvar='PROJECT_DEBUG', help="Debug mode.")
@click.pass_context
def cli(ctx, debug):
"""
Description of the CLI app.
"""
ctx.obj = CliCtx(debug)
if debug:
$XONSH_TRACE_SUBPROC = True
@cli.command()
@click.option("--use-print", default=False, is_flag=True, envvar='PROJECT_HELLO_PRINT', help="Use print() function.")
@click.pass_obj
def hello(ctx, use_print):
if ctx.debug:
print('debug: run hello')
if use_print:
print('world')
else:
echo world
if __name__ == "__main__":
cli()
```
Save this to `./cli.xsh` and run:
```xsh
chdmo +x ./cli.xsh
./cli.xsh --debug hello --use-print
# {'debug': True}
# world
```
### How to get the script path
Get the script path from `$ARGS[0]`:
```xsh
echo @("""echo This script is in @(pf"{$ARGS[0]}".parent)""") > /tmp/getpath.xsh
chmod +x /tmp/getpath.xsh
/tmp/getpath.xsh
# This script is in /tmp
```
# [History](https://xon.sh/tutorial_hist.html)
There are two history backends: `json` and [`sqlite`](https://xon.sh/tutorial_hist.html#sqlite-history-backend) which xonsh has by default. The `json` backend creates a json file with commands history on every xonsh session. The `sqlite` backend has one file with SQL-database.
We recommend using the `sqlite` backend because it saves the command on every execution, and querying of the history using SQL is very handy i.e. [history-search, history-pull](https://github.com/anki-code/xontrib-rc-awesome/blob/dfc9a8fc9a561b511262172c4ee58bd51dfc6b00/xontrib/rc_awesome.xsh#L158-L195).
```python
echo 123
# 123
__xonsh__.history[-1]
# HistoryEntry(cmd='echo 123', out='123\n', rtn=0, ts=[1614527550.2158427, 1614527550.2382812])
history info
# backend: sqlite
# sessionid: 637e577c-e5c3-4115-a3fd-99026f113464
# filename: /home/user/.local/share/xonsh/xonsh-history.sqlite
# session items: 2
# all items: 8533
# gc options: (100000, 'commands')
sqlite3 $XONSH_HISTORY_FILE "SELECT inp FROM xonsh_history ORDER BY tsb LIMIT 1;"
# echo 123
aliases['history-search'] = """sqlite3 $XONSH_HISTORY_FILE @("SELECT inp FROM xonsh_history WHERE inp LIKE '%" + $arg0 + "%' AND inp NOT LIKE 'history-%' ORDER BY tsb DESC LIMIT 10");"""
cd /tmp
history-search "cd /"
# cd /tmp
history-search! cd / # macro call
# cd /tmp
pip install sqlite_web
sqlite_web $XONSH_HISTORY_FILE # Open the database in the browser
history pull # Pull the history from parallel sessions and add to the current session. [xonsh -V > 0.13.4]
```
There is a third party history backend that's supplied in xontribs: [xontrib-history-encrypt](https://github.com/anki-code/xontrib-history-encrypt).
# [Interactive mode events](https://xon.sh/events.html)
When you're in xonsh interactive mode you can register an event, i.e.:
```python
@events.on_chdir
def mychdir(olddir, newdir, **kw):
echo Jump from @(olddir) to @(newdir)
cd /tmp
# Jump from /home/snail to /tmp
```
# [Help](https://xon.sh/tutorial.html#help-superhelp-with)
Add `?` (regular help) or `??` (super help) to the command:
```python
ls?
# man page for ls
import json
json?
# json module help
json??
# json module super help
```
# Known issues and workarounds
### ModuleNotFoundError
Sometimes when you're using PyPi, Conda, or virtual environments you can forget about the current version and location of Python and try to import packages in xonsh resulting in a `ModuleNotFoundError` error. Often this means you installed the package in another environment and didn't realise it. To avoid this read the section about xonsh installation above.
### Intersection of console tools or shell syntax with Python builtins
In case of names or syntax intersection try to use aliases or [abbrevs](https://github.com/xonsh/xontrib-abbrevs) to resolve the conflict.
The case with `elepsis`:
```xsh
aliases['...'] = 'cd ../..' # looks nice, but
...
# Elepsis
del aliases['...']
abbrevs['...'] = 'cd ../..'
... # becomes `cd ../..`
```
The case with `import`:
```xsh
cd /tmp
$PATH.append('/tmp')
echo 'echo I am import' > import && chmod +x import
import # Run subprocess `./import`
# I am import
import args # Run Python import of `args` module
# ModuleNotFoundError: No module named 'args'
aliases['imp'] = "import"
imp
# I am import
```
### Frozen terminal in interactive tools
If you run a console tool and get a frozen terminal (Ctrl+c, Ctrl+d is not working) this can be that the tool was interpreted as threaded and capturable program but the tool actually has interactive elements that expect the input from the user. There are four workarounds now:
1. Disable [THREAD_SUBPROCS](https://xon.sh/envvars.html#thread-subprocs):
```python
with ${...}.swap(THREAD_SUBPROCS=False):
./tool.sh
```
2. Run the tool in uncaptured mode:
```python
$[./tool.sh]
```
3. Set the unthreadable predictor:
```python
__xonsh__.commands_cache.threadable_predictors['tool.sh'] = lambda *a, **kw: False # use the pure name of the tool
./tool.sh
```
4. Finally, check [`$XONSH_CAPTURE_ALWAYS`](https://xon.sh/envvars.html#xonsh-capture-always) value.
### Uncaptured output
If you want to capture the output of a tool but it's not captured, there are three workarounds:
1. Add the `head` or `cat` tool at the end of the pipeline to force using the threadable mode:
```python
!(echo 123 | head -n 1000)
#CommandPipeline(
# returncode=0,
# output='123\n',
# errors=None
#)
```
2. Change threading prediction for this tool:
```python
__xonsh__.commands_cache.threadable_predictors['ssh'] = lambda *a, **kw: True
!(ssh host -T "echo 1")
#CommandPipeline(
# returncode=0,
# output='1\n',
# errors=None
#)
```
3. Wrap the tool into a bash subprocess:
```python
!(bash -c "echo 123")
#CommandPipeline(
# returncode=0,
# output='123\n',
# errors=None
#)
```
### [Bad file descriptor](https://github.com/xonsh/xonsh/issues/4224)
Using callable aliases in a long loop can cause the `Bad file descriptor` error to be raised. The workaround is to avoid using callable aliases in the loop and moving the code from callable alias directly into the loop or [marking the callable alias as unthreadable](https://xon.sh/tutorial.html#unthreadable-aliases):
```python
from xonsh.tools import unthreadable
@unthreadable
def _e():
execx('echo -n 1')
aliases['e'] = _e
for i in range(100):
e
```
# Tips and tricks
### Make your own installable xonsh RC file
Start by forking [xontrib-rc-awesome](https://github.com/anki-code/xontrib-rc-awesome).
### Triple quotes
To avoid escape character (i.e. `echo "\"hello\""`) and make string more elegant use triple quotes:
```xsh
echo """{"hello":'world'}"""
# {"hello":'world'}
```
### Python warlus operator in subprocess mode
```xsh
echo Hello @(_name := input('Name: ')) # Use `_` to keep env clean.
echo Hello again @(_name)
# Name: Mike
# Hello Mike
# Hello again Mike
```
### Using a text block in the command line
The first way is to use multiline strings:
```xsh
echo @("""
line 1
line 2
line 3
""".strip()) > file.txt
$(cat file.txt)
# 'line 1\nline 2\nline 3\n'
```
The second way is to use xonsh macro block via [xontrib-macro](https://github.com/anki-code/xontrib-macro):
```xsh
xpip install xontrib-macro
from xontrib.macro.data import Write
with! Write('/tmp/t/hello.xsh', chmod=0o700, replace=True, makedir=True, verbose=True):
echo world
/tmp/t/hello.xsh
# world
```
Run commands in docker:
```python
docker run -it --rm xonsh/xonsh:slim xonsh -c @("""
pip install --disable-pip-version-check -q lolcat
echo "We're in docker container now!" | lolcat
""")
```
Don't forget that `Alt+Enter` can run the command from any place where cursor is.
### Using the name of the alias in alias logic
```xsh
@aliases.register(",")
@aliases.register(",,")
@aliases.register(",,,")
@aliases.register(",,,,")
def _superdot():
cd @("../" * len($__ALIAS_NAME))
, # cd ../
,, # cd ../../
,,, # cd ../../../
```
### Python sugar: inline import
```xsh
# Run it or add to ~/.xonshrc
imp = type('MyClass', (object,), {'__getattr__':lambda self, name: __import__(name) })()
# Use `imp` as inline import sugar
imp.json.loads('{"a":1}')
# {'a': 1}
imp.datetime.datetime.now().isoformat()
# '2024-02-12T15:29:57.125696'
imp.hashlib.md5(b'Hello world').hexdigest()
# '3e25960a79dbc69b674cd4ec67a72c62'
```
### Ask to input argument and with autocomplete
Ask simple input:
```xsh
echo @(input('Text: '))
# Text: hello
# hello
echo Hello @(_name := input('Name: ')) # Use `_` to keep env clean.
echo Hello again @(_name)
# Name: Mike
# Hello Mike
# Hello again Mike
$ENV_NAME = input('Name: ') # Use input to set and reuse env variable
echo Name is $ENV_NAME
# Name: Alex
# Name is Alex
```
Ask input with completion:
```xsh
from prompt_toolkit import PromptSession
from prompt_toolkit.completion import WordCompleter
def ask(arg : str, completions : list = []):
completer = WordCompleter(completions)
session = PromptSession(completer=completer)
user_input = session.prompt(f'{arg}: ')
return user_input
echo I am saying @(ask('What to say'))
# What to say: hello
# I am saying hello
echo Give @(ask('Fruit', ['apple', 'banana', 'orange'])) to @(ask('To', [$(whoami).strip()]))
# Fruit: <Tab>
# Fruit: apple
# To: <Tab>
# To: user
# Give apple to user
$MY_DIR = ask('Dir', $(ls /).splitlines())
# Dir: <Tab>
```
### From the shell to REST API for one step
If you want to run shell commands from REST API you can create a [flask](https://flask.palletsprojects.com/) wrapper using [xontrib-macro](https://github.com/anki-code/xontrib-macro):
```xsh
xpip install flask xontrib-macro
cd /tmp
from xontrib.macro.data import Write
with! Write('myapi.xsh', chmod=0o700):
import json
from flask import Flask
app = Flask(__name__)
@app.route('/echo')
def index():
result = $(echo -n hello from echo) # run subprocess command
return json.dumps({'result': result})
app.run()
./myapi.xsh
# Running on http://127.0.0.1:5000
curl http://127.0.0.1:5000/echo
# {"result": "hello from echo"}
```
Don't forget [about API security](https://flask-httpauth.readthedocs.io/en/latest/#basic-authentication-examples).
### Interactively debugging a script
If you want to have a breakpoint to debug a script, use the standard Python [pdb](https://docs.python.org/3/library/pdb.html):
```xsh
xpip install xontrib-macro
from xontrib.macro.data import Write
with! Write('/tmp/run.xsh', chmod=0o700, replace=True, makedir=True):
echo hello
$VAR = 1
var = 2
import pdb
pdb.set_trace() # interactive debug
echo finish
xonsh /tmp/run.xsh
# hello
# > /tmp/run.xsh(9)<module>()
# -> echo finish
# (Pdb)
var
# 2
__xonsh__.env['VAR']
# 1
exit
# bdb.BdbQuit
```
### Using xonsh wherever you go through the SSH
You've stuffed your command shell with aliases, tools, and colors but you lose it all when using ssh. The mission of the [xxh project](https://github.com/xxh/xxh) is to bring your favorite shell wherever you go through ssh without root access or system installations.
### How to modify a command before execution?
To change the command between pressing enter and execution there is the [on_transform_command](https://xon.sh/events.html#on-transform-command) event:
```python
xpip install lolcat
@events.on_transform_command
def _(cmd, **kw):
if cmd.startswith('echo') and 'lolcat' not in cmd:
# Be careful with the condition! The modified command will be passed
# to `on_transform_command` event again and again until the event
# returns the same command. Newbies can make a mistake here and
# end up with unintended looping.
return cmd.rstrip() + ' | lolcat'
else:
return cmd
echo 123456789 # <Enter>
# Execution: echo 123456789 | lolcat
```
### Comma separated thousands in output (custom formatter)
Here is a snippet from [@maxwellfire](https://github.com/maxwellfire):
```xsh
50000+50000
# 100000
500+500.123
# 1000.123
import xonsh.pretty
xonsh.pretty.for_type(type(1), lambda int, printer, cycle: printer.text(f'{int:,}'))
xonsh.pretty.for_type(type(1.0), lambda float, printer, cycle: printer.text(f'{float:,}'))
50000+50000
# 100,000
500+500.123
# 1,000.123
```
### `chdir` [context manager](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) for scripting
```xsh
from xonsh.tools import chdir
cd /tmp
mkdir -p dir1
pwd
with chdir("./dir1"):
pwd
pwd
# /tmp
# /tmp/dir1
# /tmp
```
### Juggling of exit code using python substitution
cd-ing into directory and if count of files less then 100 run `ls`:
```xsh
aliases['cdls'] = "cd @($arg0) && @(lambda: 1 if len(g`./*`) > 100 else 0) && ls"
cdls / && pwd
# bin dev etc ...
# /
cdls /usr/sbin && pwd
# /usr/sbin
```
### How to paste and edit multiple lines of code while in interactive mode
In some terminals (Konsole in Linux or Windows Terminal for WSL) you can press `ctrl-x ctrl-e` to open up an editor (`nano` in Linux) in the terminal session, paste the code there, edit and then quit out. Your multiple line code will be pasted and executed.
### Waiting for the job done
```python
sleep 100 & # job 1
sleep 100 & # job 2
sleep 100 & # job 3
while $(jobs):
time.sleep(1)
print('Job done!')
```
### How to trace xonsh code?
Trace with [hunter](https://github.com/ionelmc/python-hunter):
```python
pip install hunter
$PYTHONHUNTER='depth_lt=10,stdlib=False' $XONSH_DEBUG=1 xonsh -c 'echo 1'
```
Or try [xunter](https://github.com/anki-code/xunter) for tracing and profiling.
### From Bash to Xonsh
Read [Bash to Xonsh Translation Guide](https://xon.sh/bash_to_xsh.html), run `bash -c! echo 123` or install [xontrib-sh](https://github.com/anki-code/xontrib-sh).
### Xonsh and Windows
First of all we recommend using [WSL 2](https://learn.microsoft.com/en-us/windows/wsl/about) with [Manjaro](https://github.com/sileshn/ManjaroWSL2) (that maintains a [rolling release](https://en.wikipedia.org/wiki/Rolling_release)) on Windows. Don't forget to [fix PATH](https://github.com/xonsh/xonsh/issues/3895#issuecomment-713078931).
But if you want to use xonsh in Windows environment:
* Install [Windows Terminal](https://github.com/microsoft/terminal) - the modern terminal emulator for Windows.
* Install [xontrib coreutils](https://xon.sh/api/_autosummary/xontribs/xontrib.coreutils.html#module-xontrib.coreutils), [cmdix](https://github.com/jaraco/cmdix), [pycoreutils](https://github.com/davidfischer/pycoreutils) - a pure Python implementation of the UNIX coreutils i.e. `echo`, `cat`, `pwd`,`ls`, etc.
* Read [Windows-specific tips and tricks](https://xon.sh/platform-issues.html#windows).
# Recipes
### Using many profiles with AWS CLI and xonsh aliases
```xsh
aws configure --profile p1
aws configure --profile p2
aliases['aws-p1'] = "$AWS_DEFAULT_PROFILE='p1' @('aws') @($args)"
aliases['aws-p2'] = "$AWS_DEFAULT_PROFILE='p2' @('aws') @($args)"
aws-p2 s3 ls s3://my-profile1-bucket/ # The same as `aws s3 ls --profile p2 s3://my-profile1-bucket/`
```
# Answers to the holy war questions
### Bash is everywhere! Why xonsh?
Python is everywhere as well ;)
### Xonsh is slower! Why xonsh?
You can spend significantly more time Googling and debugging sh-based solutions as well as significantly more time to make the payload work after running a command. Yeah, xonsh is a bit slower but you will not notice that in real life tasks :)
Also take a look:
* [Python 3.12: A Game-Changer in Performance and Efficiency](https://python.plainenglish.io/python-3-12-a-game-changer-in-performance-and-efficiency-8dfaaa1e744c)
* [Python 3.11 is up to 10-60% faster than Python 3.10](https://docs.python.org/3.11/whatsnew/3.11.html)
* [Making Python 5x FASTER with Guido van Rossum](https://www.youtube.com/watch?v=_r6bFhl6wR8).
* [RustPython](https://github.com/RustPython/RustPython) ([performance](https://user-images.githubusercontent.com/1309177/212613257-5f4bca12-6d6b-4c79-9bac-51a4c6d08928.svg) of [Ruff](https://github.com/charliermarsh/ruff) - Python linter on Rust)
### My fancy prompt in another shell is super duper! Why xonsh?
The fancy prompt is the tip of the iceberg. Xonsh shell brings other important features to love: [sane language](https://github.com/anki-code/xonsh-cheatsheet#basics), [powerful aliases](https://github.com/anki-code/xonsh-cheatsheet#aliases), [agile extensions](https://github.com/anki-code/xonsh-cheatsheet#xontrib---extension-or-plugin-for-xonsh), [history backends](https://github.com/anki-code/xonsh-cheatsheet#history), [fully customisable tab completion](https://github.com/anki-code/xonsh-cheatsheet#tab-completion), [magic macro blocks](https://github.com/anki-code/xonsh-cheatsheet#macro-block), [behaviour customisation via environment variables](https://xon.sh/envvars.html), and [more](https://github.com/anki-code/xonsh-cheatsheet#bind-hotkeys-in-prompt-toolkit-shell), and [more](https://github.com/anki-code/xonsh-cheatsheet#make-your-own-installable-xonsh-rc-file), and [more](https://github.com/anki-code/xonsh-cheatsheet#using-xonsh-wherever-you-go-through-the-ssh) :)
### Xonsh has issues! Why xonsh?
Compared to 15-20 year old shells, yeah, xonsh is a 5 year old youngster. But we've used it over these 5 years day by day to solve our tasks with success and happiness :)
# Thank you!
Thank you for reading! This cheatsheet is the tip of the iceberg of the xonsh shell and you can find more in the [official documentation](https://xon.sh/contents.html#guides).
Also you can install the cheatsheet xontrib:
```python
xpip install xontrib-cheatsheet
xontrib load cheatsheet
cheatsheet
# Opening: https://github.com/anki-code/xonsh-cheatsheet/blob/main/README.md
```
If you like the cheatsheet, click ⭐ on the repo and <a href="https://twitter.com/intent/tweet?text=The%20xonsh%20shell%20cheat%20sheet.&url=https://github.com/anki-code/xonsh-cheatsheet" target="_blank">tweet</a>.
# Credits
* [Xonsh Tutorial](https://xon.sh/tutorial.html)
* Most copy-pastable examples prepared by [xontrib-hist-format](https://github.com/anki-code/xontrib-hist-format)
* The cheat sheet xontrib was created with [xontrib cookiecutter template](https://github.com/xonsh/xontrib-cookiecutter).
Raw data
{
"_id": null,
"home_page": "https://github.com/anki-code/xontrib-cheatsheet",
"name": "xontrib-cheatsheet",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.6",
"maintainer_email": "",
"keywords": "",
"author": "anki-code",
"author_email": "no@no.no",
"download_url": "https://files.pythonhosted.org/packages/33/8d/897c20666a57731892eb7b63215dbc10d6a022effe0a36041ee717ecb5f0/xontrib-cheatsheet-0.4.4.tar.gz",
"platform": "any",
"description": "<p align=\"center\">\nCheat sheet for the <a href=\"https://xon.sh\">xonsh shell</a> with copy-pastable examples. This is a good level of knowledge to start being productive.\n<br><br>\n<img src=\"https://repository-images.githubusercontent.com/310804308/f11fa180-280d-11eb-8fa4-c389308692bd\">\n</p>\n\n<p align=\"center\">\nIf you like the cheatsheet click \u2b50 on the repo and <a href=\"https://twitter.com/intent/tweet?text=The%20xonsh%20shell%20cheat%20sheet.&url=https://github.com/anki-code/xonsh-cheatsheet\" target=\"_blank\">tweet</a> about it.\n</p>\n\n[Full screen reading](https://github.com/anki-code/xonsh-cheatsheet/blob/main/README.md)\n\n# What is xonsh?\n\nXonsh is a Python-powered, cross-platform, Unix-gazing shell language and command prompt. The language is a superset of Python 3.6+ with additional shell primitives that you are used to from [Bash](https://www.gnu.org/software/bash/) and [IPython](https://ipython.org/). It works on all Python-compatible systems, including Linux, macOS, and Windows. Try [right off the bat examples](https://github.com/anki-code/xonsh-cheatsheet/blob/main/README.md#xonsh-basics).\n\n# What does xonsh mean?\n\nThe \"xonsh\" word sounds like [conch [k\u0251\u02d0nt\u0283]](https://www.google.com/search?q=what+is+conch) - a common name of a number of different sea snails or shells (\ud83d\udc1a). Thus xonsh is the reference to the shell word that is commonly used to name [command shells](https://en.wikipedia.org/wiki/Shell_(computing)).\n\nYou will also face with \"xontrib\" word. The xontrib is short version of [\"(contrib)ution\"](https://www.collinsdictionary.com/dictionary/english/contribution) word and points to extensions, community articles and other materials around xonsh.\n\n# Install xonsh\n\nThere are three ways to use xonsh:\n\n1. **[Simple xonsh install](#simple-xonsh-install)**. You can use the system installed Python to install xonsh and dependencies. This is a good option if you don't plan to manage Python versions or virtual environments.\n\n2. **[Install xonsh with package and environment management system](#install-xonsh-with-package-and-environment-management-system)**. In this way you can flexibly manage the Python version, dependencies, and virtual environments, but because xonsh is a Python-based shell you have to understand what you're doing and the section below will provide some guidance.\n\n3. **[Try xonsh without installation](#try-xonsh-without-installation)**. Use Docker or the Linux AppImage to run and try xonsh.\n\n### Simple xonsh install\n\nMost modern operating systems have [Python](https://www.python.org/) and [PyPi (pip)](https://packaging.python.org/tutorials/installing-packages/) that are preinstalled or that can be installed easily. By installing from PyPi you will get [the latest version of the xonsh shell](https://github.com/xonsh/xonsh/releases). We highly recommend using the `full` version of the xonsh PyPi-package with [prompt-toolkit](https://python-prompt-toolkit.readthedocs.io/en/master/) on board:\n```xsh\npython -m pip install 'xonsh[full]'\n```\n\nAnother way is to install xonsh from the package manager that is supplied by the operating system. This way is _not_ recommended in operating systems without the [rolling release concept](https://en.wikipedia.org/wiki/Rolling_release) the xonsh shell version may be very old ([check latest xonsh release](https://github.com/xonsh/xonsh/releases/) or [versions of xonsh across platforms](https://repology.org/project/xonsh/versions)) because the average [release cycle for the xonsh shell](https://github.com/xonsh/xonsh/releases) is quarter.\n\n```xsh\n# Not recommended but possible\napt install xonsh # Debian/Ubuntu\ndnf install xonsh # Fedora\nbrew install xonsh # OSX\n```\n\nArch Linux *is* a rolling release system, so you are fine using that:\n\n```xsh\npacman -S xonsh python-prompt_toolkit # Arch Linux\n```\n\nOn any system you can install `python` and then install xonsh from pip i.e., `any_pkg_manager install python && python -m pip install 'xonsh[full]'` This is the preferable way.\n\n### Install xonsh with package and environment management system\n\nXonsh is a Python-based shell, and to run xonsh you must have Python installed. The Python version and its packages can be installed and located anywhere: in the operating system directories, as part of a virtual environment, as part of the user directory, or as a virtual drive created temporarily behind the scenes by the Linux AppImage.\n\nThe first thing you have to remember is that when you execute `import` or any other Python code during a xonsh session it will be executed in the Python environment that was used to run current instance of xonsh. Use the [xc alias](https://github.com/anki-code/xontrib-rc-awesome/blob/c643e4cbc5cdb88c72a0389c03c62fd5407363d2/xontrib/rc_awesome.xsh#L87) to check the xonsh context.\n\nIn other words, you can activate a virtual environment during a xonsh session (using conda, pyenv, pipx) but the current session will continue to use packages from the environment that was used to run xonsh. And if you want to run xonsh with the packages from the currently activated virtual environment you have to install xonsh in that environment and run it directly.\n\nThus the second thing you should remember is that when you run xonsh in virtual environment it will try to load [xonsh RC files](https://xon.sh/xonshrc.html#run-control-file) (i.e. `~/.xonshrc`) and because the virtual environment is different from the environement you ordinarily use, the loading of the RC file will tend to fail because of the lack of the appropriate set of packages. When you write your `~/.xonshrc` it's good practice to check the existing external dependencies before loading them. See also [xontrib-rc-awesome](https://github.com/anki-code/xontrib-rc-awesome).\n\n#### Install xonsh on macOS or Linux using conda\n\nYou can use [Conda](https://docs.conda.io/en/latest/) with [Conda-forge](https://conda-forge.org/) to install and use xonsh. \n\n```xsh\n#\n# Install python using brew\n#\nzsh # Default macOS shell\n# Install brew from https://brew.sh/\n/bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"\nbrew install python # or `python@3.11`\n\n#\n# Install Miniconda from https://docs.conda.io/en/latest/miniconda.html \n# (example for Mac, use the link for your platform)\n#\ncd /tmp\nwget https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh\nchmod +x Miniconda3-latest-MacOSX-arm64.sh\n./Miniconda3-latest-MacOSX-arm64.sh\n# Add conda init code that was printed to `~/.zshrc` and restart zsh.\n# Or run `/Users/username/miniconda3/bin/conda init zsh` to add init to ~/.zshrc and restart zsh.\n\n# After restarting zsh you will see `(base)` in prompt.\n# This means that you're in the conda `base` environment.\n\n# Switch to Conda-forge channel\nconda config --add channels conda-forge\nconda config --set channel_priority strict \nconda update --all --yes\n\n# Install xonsh to the `base` environment\nconda install xonsh\nconda init xonsh # Add init to ~/.xonshrc. You can also add `$CONDA_AUTO_ACTIVATE_BASE='false'` to avoid conda loading at start\n\nwhich xonsh\n# /Users/username/miniconda3/bin/xonsh\n\n# Run xonsh from the `base` environment\nxonsh\n```\nHow to work and understand the environments in conda:\n```xsh\n# `xpip` is used to install packages to the current xonsh session location (now it's `base` environment)\nxpip install ujson \n\n# Example of creating the environment with a certain version of Python\nconda search python | grep 3.10\nconda create -n \"py310\" python=3.10 xonsh\n\nconda activate py310\n# Now the environment is `py310` but current xonsh session is still in `base` environment\n\nwhich xonsh\n# /Users/username/miniconda3/envs/py310/bin/xonsh\n\nwhich pip\n# /Users/username/miniconda3/envs/py310/bin/pip # pip from `py310`\n\nwhich xpip\n# /Users/username/miniconda3/bin/pip # pip from `base` environment from where xonsh ran\n\n# Run xonsh that installed in `py310` environment from xonsh runned in `base` environment\nxonsh\nconda activate py310\n# Now xonsh session is in `py310` environment and the current environment is also `py310`\n\nimport ujson\n# No module named 'ujson' # YES because ujson was installed in `base` environment\n```\n\nOn Mac we also recommend to install [GNU coreutils](https://www.gnu.org/software/coreutils/) to use the Linux default tools (i.e. `ls`, `grep`):\n```xsh\nbrew install coreutils\n$PATH.append('/opt/homebrew/opt/coreutils/libexec/gnubin') # add to ~/.xonshrc\n```\n\n#### How to understand the xonsh location\n\nWhich xonsh and which Python used to run the **current** xonsh session:\n\n```xsh\nimport sys\n[sys.argv[0], sys.executable]\n# ['/opt/homebrew/bin/xonsh', '/opt/homebrew/opt/python@3.11/bin/python3.11']\n\n\n@(sys.executable) -m site\n# Full info about paths\n```\n\nWhich `xonsh` and which `python` that will be executed to run **new instances** depends on the list of directories in `$PATH` or virtual environment:\n\n```xsh\n$PATH\n# ['/home/user/miniconda3/bin', '/opt/homebrew/bin]\n\n[$(ls -la @$(which xonsh)), $(ls -la @$(which python)), $(python -V)]\n# ['/home/user/miniconda3/bin/xonsh', '/home/user/miniconda3/bin/python -> python3.11', 'Python 3.11.1']\n\npython -m site\n# Full info about paths\n```\n\n#### pipx and xonsh\n\nThe [pipx](https://pipxproject.github.io/pipx/) tool is also good to install xonsh in case you need certain Python version:\n```xsh\n# Install Python before continuing\npip install pipx\npipx install --python python3.8 xonsh # Here `python3.8` is the path to installed python. \npipx run xonsh \n# or add /home/$USER/.local/bin to PATH (/etc/shells) to allow running just the `xonsh` command\n```\n\n### Try xonsh without installation\n\n#### Docker\n\n```python\n# Docker with specific Python version and latest release of xonsh\ndocker run --rm -it python:3.11-slim /bin/bash \\\n -c \"pip install 'xonsh[full]' && xonsh\"\n\n# Docker with specific Python version and xonsh from the master branch\ndocker run --rm -it python:3.11-slim /bin/bash \\\n -c \"apt update && apt install -y git && pip install -U git+https://github.com/xonsh/xonsh && xonsh\"\n\n# Official xonsh docker image may has an old version\ndocker run --rm -it xonsh/xonsh:slim\n```\n\n#### Linux-portable AppImage contains both [Python 3 and xonsh in one file](https://xon.sh/appimage.html)\n\n```python\nwget https://github.com/xonsh/xonsh/releases/latest/download/xonsh-x86_64.AppImage -O xonsh\nchmod +x xonsh\n./xonsh\n\n# Then if you don\u2019t have Python on your host, you can acccess it from the AppImage by running:\n$PATH = [$APPDIR + '/usr/bin'] + $PATH\npython -m pip install tqdm --user # the `tqdm` package will be installed to ~/.local/\nimport tqdm\n```\n\nYou can [build your own xonsh AppImage](https://xon.sh/appimage.html#building-your-own-xonsh-appimage) with the packages you need in 15 minutes.\n\n# Xonsh basics\n\nThe xonsh language is a superset of Python 3 with additional shell support. As result you can mix shell commands and Python code as easily as possible. Right off the bat examples:\n\n```xsh\ncd /tmp && ls # shell commands\n\n21 + 21 # python command\n\nfor i in range(0, 42): # mix python \n echo @(i+1) # and the shell\n\nlen($(curl https://xon.sh)) # mix python and the shell\n\n$PATH.append('/tmp') # using environment variables\n\np'/etc/passwd'.read_text().find('root') # path-string returns Path \n # (https://docs.python.org/3/library/pathlib.html)\n\nfor line in $(cat /etc/passwd).splitlines(): # read the lines from the output\n echo @(line.split(':')[0]) # prepare line on Python and echo\n\nfor file in gp`*.*`: # reading the list of files as Path-objects\n if file.exists(): # using rich functionality of Path-objects\n du -sh @(file) # and pass it to the shell command\n\nimport json # python libraries are always at hand\nif docker_info := $(docker info --format '{{json .}}'):\n print('ContainersRunning:', json.loads(docker_info)['ContainersRunning'])\n\nxpip install xontrib-prompt-bar # xonsh has huge amount of powerful extensions\nxontrib load prompt_bar # follow the white rabbit - https://github.com/topics/xontrib\n\n# Finally fork https://github.com/anki-code/xontrib-rc-awesome\n# to convert your ~/.xonshrc into a pip-installable package \n# with the extensions you need on board.\n```\n\nLooks nice? [Install xonsh](#install-xonsh)!\n\n## Three most frequent things that newcomers overlook\n\n### 1. [Shell commands, also known as subprocess commands](https://xon.sh/tutorial.html#python-mode-vs-subprocess-mode)\n\nThe first thing you should remember is that the shell commands are not the calls of another shell (i.e. bash). Xonsh has its own parser implementation for subprocess commands, and this is why a command like `echo {1..5} \\;` (brace expansion and escape characters in bash) won't work. Most sh-shell features [can be replaced](https://xon.sh/bash_to_xsh.html) by sane Python alternatives. For example, the earlier command could be expressed as `echo @(range(1,6)) ';'`.\n\nIf you think that only xonsh has the sh-uncompatible elements in its parser, you are mistaken. If we compare Bash and Zsh we will find that `pip install package[subpackage]` command will work in Bash but in Zsh the error will be raised because Zsh has a special meaning for square braces. It's normal to have an evolution in the syntax and features. \n\nBe calm and accept the sane and self-consistent Python-driven mindset.\n\n*Note:*\n\n* *Most of novice try to copy and paste sh-lang commands that contain special characters and get syntax errors in xonsh. If you want to run environment agnostic sh-lang's commands that you copy from the internet just use the macro call in xonsh `bash -c! echo {123}` or use [xontrib-sh](https://github.com/anki-code/xontrib-sh) to run context-free bash commands in xonsh by adding `! ` at the beginning of the command.*\n* *We highly recommend to taking a look at the section [Install xonsh with package and environment management system](#install-xonsh-with-package-and-environment-management-system).*\n\n\n### 2. [Strings and arguments in shell commands](https://xon.sh/tutorial_subproc_strings.html)\n\nThe second potential misunderstanding comes from the first. To escape special charecters, the special meaning of braces, or pass a string as an argument, use quotes. When in doubt, use quotes!\n\nYou should clearly understand the difference:\n\n <table style=\"width:100%\">\n <tr>\n <th>sh-lang shells</th>\n <th>xonsh</th>\n </tr>\n<tr>\n<td>\n1. Has an escape character:\n<pre>\n<b>echo 123\\ 456</b>\n# 123 456\n</pre>\n</td>\n <td>\n1. Use quotes:\n<pre>\n<b>echo \"123 456\"</b>\n# 123 456\n</pre>\n<a href=\"https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals\">Escape character</a> to wrap and so on:\n<pre>\n<b>echo \"123\\\n456\"</b>\n# 123456\n</pre>\n\n</td>\n </tr>\n\n<tr>\n<td>\n2. Open the quotes:\n<pre>\n<b>echo --arg=\"val\"</b>\n# --arg=val<br>\n# and:<br>\n<b>echo --arg \"val\"</b>\n# --arg val\n\n</pre>\n</td>\n <td>\n2. Save quotes:\n<pre>\n<b>echo --arg=\"val\"</b>\n# --arg=\"val\"<br>\n# But if argument quoted entirely:<br>\n<b>echo --arg \"val\"</b>\n# --arg val\n</pre>\n</td>\n </tr>\n\n<tr>\n<td>\n3. Brackets have no meaning:\n<pre>\n<b>echo {123} [456]</b>\n# {123} [456]<br><br><br>\n</pre>\n</td>\n <td>\n3. Brackets have meaning:\n<pre>\n<b>echo {123} [456]</b>\n# SyntaxError<br>\n<b>echo \"{123}\" '[456]'</b>\n# {123} [456]\n</pre>\n</td>\n </tr>\n</table> \n\n*Note:*\n\n* *You can wrap any argument into Python string substitution:*\n ```python\n name = 'snail'\n echo @('--name=' + name.upper())\n # --name=SNAIL\n ```\n* *You can use the `showcmd` command to show the arguments list:* \n ```python\n showcmd echo The @('arguments') @(['list', 'is']) $(echo here) \"and\" --say=\"hello\" to you\n # ['echo', 'The', 'arguments', 'list', 'is', 'here\\n', 'and', '--say=\"hello\"', 'to', 'you']] \n ```\n\n\n### 3. The process substitution operator `$()` returns output with [universal new lines](https://www.python.org/dev/peps/pep-0278/)\n\nIn sh-compatible shells, the [process substitution operator](https://en.wikipedia.org/wiki/Process_substitution) `$()` executes the command and then splits the output and uses those parts as arguments. The command `echo $(echo -e \"1 2\\n3\")` will have three distinct arguments, `1`, `2` and `3` that will passed to the first `echo`.\n\nIn xonsh shell the `$()` operator returns the output of the command. The command `echo $(echo -e \"1 2\\n3\")` will have one argument, `1 2\\n3\\n` that will be passed to the first `echo`.\n\n*Note:*\n\n* *To do what sh-compatible shells are doing with the `$()` operator, the xonsh shell has the `@$()` operator that will be described in the next chapter.*\n ```python\n showcmd echo @$(echo \"1\\n2 3\\n4\")\n # ['echo', '1', '2', '3', '4']\n ```\n* *To transform output to the lines for the arguments list you can use [splitlines](https://docs.python.org/3/library/stdtypes.html#str.splitlines) function and the python substitution:*\n ```python\n showcmd echo @($(echo \"1\\n2 3\\n4\").splitlines()) # the first echo will get three arguments: \"1\", \"2 3\", \"4\"\n # ['echo', '1', '2 3', '4']\n ```\n* *Not all xonsh users like this behavior of `$()` operator, and in the future, this may be changed. There is [a thread to discussing](https://github.com/xonsh/xonsh/issues/3924) this and the [Xonsh Enhancement Proposal #2](https://github.com/anki-code/xonsh-operators-proposal/blob/main/XEP-2.rst).*\n\n# [Operators](https://xon.sh/tutorial.html#captured-subprocess-with-and)\n\n### `$()` - capture and return output without printing stdout and stderr\n\nCaptures stdout and returns output with [universal new lines](https://www.python.org/dev/peps/pep-0278/):\n```python\nshowcmd $(echo -e '1\\n2\\r3 4\\r\\n5') # Subproc mode\n# ['1\\n2\\n3 4\\n5\\n']\n\noutput = $(echo -e '1\\n2\\r3 4\\r\\n5') # Python mode \noutput\n# '1\\n2\\n3 4\\n5\\n'\n```\n\n### `!()` - capture all and return object without printing stdout and stderr\n\nCaptures stdout and returns [CommandPipeline](https://xon.sh/api/procs/pipelines.html#xonsh.procs.pipelines.CommandPipeline). Truthy if successful (returncode == 0), compares to, iterates over lines of stdout:\n \n```python\nret = !(echo 123)\nret\n#CommandPipeline(\n# pid=404136,\n# returncode=0,\n# args=['echo', '123'],\n# alias=None,\n# timestamps=[1604742882.1826484, 1604742885.1393967],\n# executed_cmd=['echo', '123'],\n# input='',\n# output='123\\n',\n# errors=None\n#) \n\nif ret:\n print('Success') \n#Success\n\nfor l in ret:\n print(l) \n#123\n#\n\n```\n\nNote! In some cases, to get the output you need to convert an object to a string or invoke [`.end()`](https://github.com/xonsh/xonsh/blob/6d58fb5bf7c62fa5c56721b62f40b214f83822eb/xonsh/procs/pipelines.py#L450-L459) manually or use the `.out`:\n\n```xsh\nr = !(ls /)\nr.output\n# ''\n\nr.end()\nr.output\n# 'bin\\netc\\n...'\n\nr = !(ls /)\nr.out # out is forcing ending\n# 'bin\\netc\\n...'\n\nr = !(ls /)\nprint(r) # r will be converted to str and the ending will be forced\n# bin\n# etc\n# ...\n```\n\n### `$[]` - not capturing (return `None`), print stdout and stderr\n\nPasses stdout to the screen and returns `None`:\n\n```python\nret = $[echo 123]\n# 123\nrepr(ret)\n# 'None'\n```\n\nThis is the same as `echo 123`, but this syntax allows explicitly running a subprocess command.\n\n### `![]` - capture all and return hidden object, print stdout and stderr\n\n*Note! The behavior may be different if [`$XONSH_CAPTURE_ALWAYS`](https://xon.sh/envvars.html#xonsh-capture-always) is True or False (default).*\n\nPasses stdout to the screen and returns [HiddenCommandPipeline](https://xon.sh/api/procs/pipelines.html#xonsh.procs.pipelines.HiddenCommandPipeline):\n\n```python\nwith __xonsh__.env.swap(XONSH_CAPTURE_ALWAYS=True):\n ret = ![echo -e '1\\n2\\r3 4\\r\\n5']\n # 1 # Stream output of the command\n # 3 4\n # 5\n ret # No return value because it's HiddenCommandPipeline object\n ret.out # But it has the properties from CommandPipeline\n # '1\\n2\\r3 4\\n5\\n'\n```\n\nThis operator is used under the hood for running commands at the interactive xonsh prompt.\n\n### `@()` - use Python code as an argument or a callable alias\n\nEvaluates Python and passes the arguments:\n\n```python\nshowcmd 'Supported:' @('string') @(['list','of','strings']) \n#['Supported:', 'string', 'list', 'of', 'strings']\n\necho -n '!' | @(lambda args, stdin: 'Callable' + stdin.read())\n#Callable!\n```\n\n### `@$()` - split output of the command by white spaces for arguments list\n\n```python\nshowcmd @$(echo -e '1\\n2\\r3 4\\r\\n5')\n#['1', '2\\r3', '4', '5']\n```\nThis is mostly [what bash's `$()` operator does](https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html).\n\n# [Environment Variables](https://xon.sh/tutorial.html#environment-variables)\n\n```python\n${...} # Get the list of environment variables\n__xonsh__.env # Get the list of environment variables using Python syntax\n\n$VAR = 'value' # Set environment variable\n\nENV = ${...} # short typing\nENV.get('VAR', 'novalue') # the good practice to have a fallback for missing value\n# 'value'\nENV.get('VAR2', 'novalue') # the good practice to have a fallback for missing value\n# 'novalue'\n\n'VAR' in ${...} # Check environment variable exists\n#True\n\n${'V' + 'AR'} # Get environment variable value by name from expression\n#'value'\n\nprint($VAR)\nwith ${...}.swap(VAR='another value', NEW_VAR='new value'): # Change VAR for commands block\n print($VAR)\nprint($VAR)\n#value\n#another value\n#value\n\n$VAR='new value' xonsh -c r'echo $VAR' # Change variable for subprocess command\n#new value\n\n__xonsh__.env.get('VAR', 'novalue') # the way to call environment using the __xonsh__ builtin\n# 'value'\n```\n\nPython and subprocess mode:\n```python\nprint(\"my home is $HOME\") # Python mode\n# my home is $HOME\n\nprint(\"my home is \" + $HOME) # Python mode\n# my home is /home/snail\n\necho \"my home is $HOME\" as well as '$HOME' # Subprocess mode\n# my home is /home/snail as well as /home/snail\n```\n\nWork with [`$PATH`](https://xon.sh/envvars.html#path):\n```python\n$PATH\n# EnvPath(\n# ['/usr/bin',\n# '/sbin',\n# '/bin']\n# )\n\n$PATH.add(p\"~/bin\", front=True, replace=True)) # Insert path '~/bin' at front of $PATH list and replace existing entries\n$PATH.add(p\"~/bin\", front=True) # Insert path '~/bin' at front of $PATH list\n$PATH.add(p\"~/bin\", front=False, replace=True)) # Insert path '~/bin' at end of $PATH list and replace existing entries\n$PATH.insert(0, '/tmp') # Insert path '/tmp' at front of $PATH list\n$PATH.append('/tmp') # Append path '/tmp' at end of $PATH list\n$PATH.remove('/tmp') # Remove path '/tmp' (first match)\n```\n\nSetup local paths by prepending to path via a loop in `.xonshrc`:\n```python\nimport os.path\nfrom os import path\n$user_bins = [\n f'{$HOME}/.cargo/bin',\n f'{$HOME}/.pyenv/bin',\n f'{$HOME}/.poetry/bin',\n f'{$HOME}/bin',\n f'{$HOME}/local/bin',\n f'{$HOME}/.local/bin', \n]\n\nfor dir in $user_bins:\n if path.isdir(dir) and path.exists(dir):\n $PATH.add(dir,front=True, replace=True)\n```\n\nSee also the list of [xonsh default environment variables](http://xon.sh/envvars.html).\n\n# [Aliases](https://xon.sh/tutorial.html#aliases)\n\n## Simple aliases\n\n```python\naliases['g'] = 'git status -sb' # Add alias as string\naliases['e'] = 'echo @(2+2)' # Add xonsh executable alias (ExecAlias)\naliases['gp'] = ['git', 'pull'] # Add alias as list of arguments\naliases['b'] = lambda: \"Banana!\\n\" # Add alias as simple callable lambda\naliases |= {'a': 'echo a', 'b':'echo b'} # Add aliases from the dict\ndel aliases['b'] # Delete alias\n```\n\nEasy wrapping a command by using [ExecAlias](https://xon.sh/tutorial.html#aliases) with built-in [`$args`](https://xon.sh/tutorial.html#aliases) (or `$arg0`, `$arg1`, etc) variable:\n\n```python\naliases['echo-new'] = \"echo @($args) new\"\n$(echo-new hello)\n# 'hello new\\n'\n$(echo-new -n hello)\n# 'hello new'\n```\n\nAlso with handy `\"\"\"`-string to use `\"` and `'` without escaping:\n\n```python\naliases['scmd'] = \"\"\"showcmd @([a for a in $args if a != \"cutme\"])\"\"\"\n\nscmd\n# usage: showcmd [-h|--help|cmd args]\n# Displays the command and arguments as a list ...\n\nscmd 1 2 cutme 3\n#['1', '2', '3']\n```\n\n## [Callable aliases](https://xon.sh/tutorial.html#callable-aliases)\n\n```python\ndef _myargs1(args):\n#def _myargs2(args, stdin=None):\n#def _myargs3(args, stdin=None, stdout=None):\n#def _myargs4(args, stdin=None, stdout=None, stderr=None):\n#def _myargs5(args, stdin=None, stdout=None, stderr=None, spec=None):\n#def _myargs6(args, stdin=None, stdout=None, stderr=None, spec=None, stack=None):\n print(args)\n \naliases['args'] = _myargs1\ndel _myargs1\n\nargs 1 2 3\n#['1', '2', '3']\n```\n\nSimple definition with [decorator](https://wiki.python.org/moin/PythonDecorators#What_is_a_Python_Decorator):\n```xsh\n@aliases.register(\"hello\")\ndef __hello():\n echo world\n \nhello\n# world\n```\n\nRead stdin and write to stdout (real-life example - [xontrib-pipeliner](https://github.com/anki-code/xontrib-pipeliner)):\n```xsh\n# Add an exclamation point to each line\ndef _exc(args, stdin, stdout):\n for line in stdin.readlines():\n print(line.strip() + '!', file=stdout, flush=True)\n\naliases['exc'] = _exc\n\necho hello | exc\n# hello!\n```\n```xsh\n# JSON to YAML\n@aliases.register(\"j2y\")\ndef __j2y(args, stdin, stdout):\n import json, yaml\n print(yaml.dump(json.loads(stdin.read())), file=stdout)\n\n# YAML to JSON\n@aliases.register(\"y2j\")\ndef __y2j(args, stdin, stdout):\n import yaml, json\n json.dump(yaml.safe_load(stdin), stdout, indent=4)\n\necho '{\"hello\":{\"world\":\"42\"}}' | j2y\n# hello:\n# world: 42\n\necho 'hello:\\n world: 42' | y2j\n# {\n# \"hello\": {\n# \"world\": \"42\"\n# }\n# }\n```\n## Abbrevs\n\nThere is [xontrib-abbrevs](https://github.com/xonsh/xontrib-abbrevs) as alternative to aliases. You can create abbrev and set the position of editing:\n```xsh\nxpip install xontrib-abbrevs\nxontrib load abbrevs\n\nabbrevs['gst'] = 'git status'\ngst # Once you hit <space> or <return> 'gst' gets expanded to 'git status'.\n\nabbrevs['gp'] = \"git push <edit> --force\" # Set the edit position.\nabbrevs['@'] = \"@(<edit>)\" # Make shortcut.\nabbrevs['...'] = \"cd ../..\" # Workaround for syntax intersections with Python i.e. `elepsis` object from Python here.\n\n# You can set a callback that receives current command buffer and word that triggered abbrev\nabbrevs['*'] = lambda buffer, word: \"asterisk\" if buffer.text.startswith('echo') else word\nls * # will stay\necho * # will be transformed to `echo asterisk`\n```\n\n# [Path strings](https://xon.sh/tutorial.html#advanced-string-literals)\n\nThe p-string returns [Path object](https://docs.python.org/3/library/pathlib.html):\n\n```python\npath = p'~/.xonshrc'\npath\n# Path('/home/snail/.xonshrc')\n\n[path.name, path.exists(), path.parent]\n# ['.xonshrc', True, Path('/home/snail')]\n\n[f for f in path.parent.glob('*') if 'xonsh' in f.name]\n# [Path('/home/snail/.xonshrc')]\n\ndir1 = 'hello'\ndir2 = 'world'\npath = p'/tmp' / dir1 / dir2 / 'from/dir' / f'{dir1}'\npath\n# Path('/tmp/hello/world/from/dir/hello')\n```\n\nA simple way to read and write the file content using Path string:\n\n```python\ntext_len = p'/tmp/hello'.write_text('Hello world')\ncontent = p'/tmp/hello'.read_text()\ncontent\n# 'Hello world'\n```\n\n\n# [Globbing](https://xon.sh/tutorial.html#normal-globbing) - get the list of files from path by mask or regexp\nTo [Normal globbing](https://xon.sh/tutorial.html#normal-globbing) add `g` before back quotes:\n```python\nls *.*\nls g`*.*`\n\nfor f in gp`/tmp/*.*`: # `p` is to return path objects\n print(f.name)\n \nfor f in gp`/tmp/*/**`: # `**` is to glob subdirectories\n print(f)\n\n```\nTo [Regular Expression Globbing](https://xon.sh/tutorial.html#regular-expression-globbing) add `r` before back quotes:\n```python\nls `.*`\nls r`.*`\n\nfor f in rp`.*`: # `p` is to return path instances\n print(f.exists())\n```\nTo [Custom function globbing](https://xon.sh/tutorial.html#custom-path-searches) add `@` and the function name before back quotes:\n```python\ndef foo(s):\n return [i for i in os.listdir('.') if i.startswith(s)]\ncd /\n@foo`bi`\n#['bin']\n```\n\n# Macros\n\n## [Simple macros](https://xon.sh/tutorial_macros.html#function-macros)\n\n```python\ndef m(x : str):\n return x\n\n# No macro calls:\n[m('me'), m(42), m(m)]\n# ['me', 42, <function __main__.m>]\n\n# Macro calls:\n[m!('me'), m!(42), m!(identity), m!(42), m!( 42 ), m!(import os)]\n# [\"'me'\", '42', 'identity', '42', '42', 'import os']\n\nm!(if True:\n pass)\n# 'if True:\\n pass'\n```\n\n## [Subprocess Macros](https://xon.sh/tutorial_macros.html#subprocess-macros)\n\n```python\necho! \"Hello!\"\n# \"Hello!\"\n\nbash -c! echo \"Hello!\"\n# Hello!\n\ndocker run -it --rm xonsh/xonsh:slim xonsh -c! 2+2\n# 4\n```\n\nInside of a macro, all [additional munging](https://xon.sh/tutorial.html#string-literals-in-subprocess-mode) is turned off:\n\n```python\n\necho $USER\n# lou\n\necho! $USER\n# $USER\n```\n\n## [Macro block](https://xon.sh/tutorial_macros.html#context-manager-macros)\n\n### Builtin macro Block\n```python\nfrom xonsh.contexts import Block\nwith! Block() as b:\n qwe\n asd\n zxc\n\nb.macro_block\n# 'qwe\\nasd\\nzxc\\n\\n'\nb.lines\n# ['qwe', 'asd', 'zxc', '']\n```\n\n### Custom JSON block\n```python\nimport json\n\nclass JsonBlock:\n __xonsh_block__ = str\n\n def __enter__(self):\n return json.loads(self.macro_block)\n\n def __exit__(self, *exc):\n del self.macro_block, self.macro_globals, self.macro_locals\n\n\nwith! JsonBlock() as j:\n {\n \"Hello\": \"world!\"\n }\n \nj['Hello']\n# world!\n```\n\n### Custom Docker block\n\nThe example is from [xontrib-macro-lib](https://github.com/anki-code/xontrib-macro-lib):\n\n```python\nfrom xonsh.contexts import Block\n\nclass Doxer(Block):\n \"\"\"Run xonsh codeblock in docker container.\"\"\"\n\n def __init__(self):\n self.docker_image = 'xonsh/xonsh:slim'\n\n def __exit__(self, *a, **kw):\n $[docker run -it --rm @(self.docker_image) /usr/local/bin/xonsh -c @(self.macro_block)]\n\n\nwith! Doxer() as d:\n pip install lolcat\n echo \"We're in docker container now!\" | lolcat\n```\n\n### Macro blocks library\n\nSee also [xontrib-macro-lib](https://github.com/anki-code/xontrib-macro-lib).\n\n# [Tab-Completion](https://xon.sh/tutorial_completers.html)\n\n```python\ncompleter list # List the active completers\n```\nTake a look into [xontrib-fish-completer](https://github.com/xonsh/xontrib-fish-completer) - it provides more rich completion than default bash completer.\n\nCreate your own completer:\n```\ndef dummy_completer(prefix, line, begidx, endidx, ctx):\n '''\n Completes everything with options \"lou\" and \"carcolh\",\n regardless of the value of prefix.\n '''\n return {\"lou\", \"carcolh\"}\n \ncompleter add dummy dummy_completer # Add completer: `completer add <NAME> <FUNC>`\n# Now press Tab key and you'll get {\"lou\", \"carcolh\"} in completions\ncompleter remove dummy\n```\n\n# Bind hotkeys in prompt toolkit shell\n\nUncover the power of [prompt_toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit#python-prompt-toolkit) by [binding](https://xon.sh/tutorial_ptk.html) the [hotkeys](https://github.com/prompt-toolkit/python-prompt-toolkit/blob/master/src/prompt_toolkit/keys.py). Run this snippet or add it to `~/.xonshrc`:\n\n```python\nfrom prompt_toolkit.keys import Keys\n\n@events.on_ptk_create\ndef custom_keybindings(bindings, **kw):\n\n # Press F1 and get the list of files\n @bindings.add(Keys.F1) # or for Mac try `@bindings.add(\"c-k\") # control+k`\n def run_ls(event):\n ls -l\n event.cli.renderer.erase()\n \n # Press F3 to insert the grep command\n @bindings.add(Keys.F3) # or for Mac try `@bindings.add(\"c-k\") # control+k`\n def add_grep(event):\n event.current_buffer.insert_text('| grep -i ')\n\n # Clear line by pressing `Escape` key\n @bindings.add(\"escape\")\n def clear_line(event):\n event.current_buffer.delete_before_cursor(1000)\n \n```\n\nSee also: [more about key bindings](https://python-prompt-toolkit.readthedocs.io/en/master/pages/advanced_topics/key_bindings.html), [event.current_buffer](https://python-prompt-toolkit.readthedocs.io/en/stable/pages/reference.html#prompt_toolkit.buffer.Buffer).\n\n# [Xontrib](https://xon.sh/tutorial_xontrib.html) - extension or plugin for xonsh\n\nXontrib lists: \n* [Github topic](https://github.com/topics/xontrib)\n* [Github repositories](https://github.com/search?q=xontrib-&type=repositories)\n* [awesome-xontribs](https://github.com/xonsh/awesome-xontribs)\n\nTo install xontribs xonsh has [`xpip`](https://xon.sh/aliases.html?highlight=aliases#xpip) - a predefined alias pointing to the pip command associated with the Python executable running this xonsh. Using `xpip` is the right way to install xontrib to be confident that the xontrib will be installed in the right environment.\n\nIf you want to create your own xontrib [using xontrib-template](https://github.com/xonsh/xontrib-template) is the best way:\n```python\nxpip install copier jinja2-time cookiecutter\ncopier gh:xonsh/xontrib-template .\n```\n\n# Xonsh Script (xsh)\n\nReal-life example of xsh script that has: arguments, tab completion for arguments (using [xontrib-argcomplete](https://github.com/anki-code/xontrib-argcomplete)), subprocess calls with checking the result, colorizing the result and exit code:\n```python\n#!/usr/bin/env xonsh\n# PYTHON_ARGCOMPLETE_OK \nimport argparse\nimport argcomplete # Tab completion support with xontrib-argcomplete\nfrom argcomplete.completers import ChoicesCompleter\n\n$RAISE_SUBPROC_ERROR = True # Raise an error if a subprocess returns a non-zero exit status.\n # Read more: https://xon.sh/envvars.html#raise-subproc-error\n\nargp = argparse.ArgumentParser(description=f\"Get count of lines in HTML by site address.\")\nargp.add_argument('--host', required=True, help=\"Host\").completer=ChoicesCompleter(('xon.sh', 'github.com'))\nargcomplete.autocomplete(argp)\nargs = argp.parse_args()\n\nif result := !(curl -s -L @(args.host)): # Python + Subprocess = \u2665\n lines_count = len(result.out.splitlines())\n printx(f'{{GREEN}}Count of lines on {{#00FF00}}{args.host}{{GREEN}}: {{YELLOW}}{lines_count}{{RESET}}')\nelse:\n printx(f'{{RED}}Error while reading {{YELLOW}}{args.host}{{RED}}! {{RESET}}') # Colorizing messages\n exit(1) # Exit with code number 1\n```\nTry it in action:\n```python\nxonsh\npip install argcomplete xontrib-argcomplete\nxontrib load argcomplete\ncd /tmp\nwget https://raw.githubusercontent.com/anki-code/xonsh-cheatsheet/main/examples/host_lines.xsh\nchmod +x host_lines.xsh\n./host_lines.xsh --ho<Tab>\n./host_lines.xsh --host <Tab>\n./host_lines.xsh --host xon.sh\n# Count of lines on xon.sh: 568\n```\n\nTo make the interaction with script more awesome [use `click`, `typer` and `rich`](https://betterprogramming.pub/designing-beautiful-command-line-applications-with-python-72bd2f972ea):\n\n```xsh\n\"\"\"Example of CLI application.\"\"\"\n\nimport click\n\nclass OrderCommands(click.Group):\n def list_commands(self, ctx: click.Context) -> list[str]:\n return list(self.commands)\n\n\nclass CliCtx:\n \"\"\"CLI application sharable context.\"\"\"\n def __init__(self, debug):\n self.debug = debug\n\n if self.debug:\n # Show arguments in debug mode.\n from pprint import pprint\n pprint(vars(self))\n\n\n@click.group(cls=OrderCommands) # The list of commands in `--help` will be the same as the functions declarations order.\n@click.option(\"--debug\", default=False, is_flag=True, envvar='PROJECT_DEBUG', help=\"Debug mode.\")\n@click.pass_context\ndef cli(ctx, debug):\n \"\"\"\n Description of the CLI app.\n \"\"\"\n ctx.obj = CliCtx(debug)\n\n if debug:\n $XONSH_TRACE_SUBPROC = True\n\n\n@cli.command()\n@click.option(\"--use-print\", default=False, is_flag=True, envvar='PROJECT_HELLO_PRINT', help=\"Use print() function.\")\n@click.pass_obj\ndef hello(ctx, use_print):\n if ctx.debug:\n print('debug: run hello')\n\n if use_print:\n print('world')\n else:\n echo world\n\n\nif __name__ == \"__main__\":\n cli()\n```\nSave this to `./cli.xsh` and run:\n```xsh\nchdmo +x ./cli.xsh\n./cli.xsh --debug hello --use-print\n# {'debug': True}\n# world\n```\n\n\n### How to get the script path\n\nGet the script path from `$ARGS[0]`:\n\n```xsh\necho @(\"\"\"echo This script is in @(pf\"{$ARGS[0]}\".parent)\"\"\") > /tmp/getpath.xsh\nchmod +x /tmp/getpath.xsh\n/tmp/getpath.xsh\n# This script is in /tmp\n```\n\n# [History](https://xon.sh/tutorial_hist.html)\n\nThere are two history backends: `json` and [`sqlite`](https://xon.sh/tutorial_hist.html#sqlite-history-backend) which xonsh has by default. The `json` backend creates a json file with commands history on every xonsh session. The `sqlite` backend has one file with SQL-database.\n\nWe recommend using the `sqlite` backend because it saves the command on every execution, and querying of the history using SQL is very handy i.e. [history-search, history-pull](https://github.com/anki-code/xontrib-rc-awesome/blob/dfc9a8fc9a561b511262172c4ee58bd51dfc6b00/xontrib/rc_awesome.xsh#L158-L195).\n\n```python\necho 123\n# 123\n\n__xonsh__.history[-1]\n# HistoryEntry(cmd='echo 123', out='123\\n', rtn=0, ts=[1614527550.2158427, 1614527550.2382812])\n\nhistory info\n# backend: sqlite\n# sessionid: 637e577c-e5c3-4115-a3fd-99026f113464\n# filename: /home/user/.local/share/xonsh/xonsh-history.sqlite\n# session items: 2\n# all items: 8533\n# gc options: (100000, 'commands')\n\nsqlite3 $XONSH_HISTORY_FILE \"SELECT inp FROM xonsh_history ORDER BY tsb LIMIT 1;\"\n# echo 123\n\naliases['history-search'] = \"\"\"sqlite3 $XONSH_HISTORY_FILE @(\"SELECT inp FROM xonsh_history WHERE inp LIKE '%\" + $arg0 + \"%' AND inp NOT LIKE 'history-%' ORDER BY tsb DESC LIMIT 10\");\"\"\"\ncd /tmp\nhistory-search \"cd /\"\n# cd /tmp\nhistory-search! cd / # macro call\n# cd /tmp\n\npip install sqlite_web\nsqlite_web $XONSH_HISTORY_FILE # Open the database in the browser\n\nhistory pull # Pull the history from parallel sessions and add to the current session. [xonsh -V > 0.13.4]\n```\n\nThere is a third party history backend that's supplied in xontribs: [xontrib-history-encrypt](https://github.com/anki-code/xontrib-history-encrypt).\n\n# [Interactive mode events](https://xon.sh/events.html)\n\nWhen you're in xonsh interactive mode you can register an event, i.e.:\n\n```python\n@events.on_chdir\ndef mychdir(olddir, newdir, **kw):\n echo Jump from @(olddir) to @(newdir)\n \ncd /tmp\n# Jump from /home/snail to /tmp\n```\n\n# [Help](https://xon.sh/tutorial.html#help-superhelp-with)\n\nAdd `?` (regular help) or `??` (super help) to the command:\n\n```python\nls?\n# man page for ls\n\nimport json\njson?\n# json module help\njson??\n# json module super help\n```\n\n# Known issues and workarounds\n\n### ModuleNotFoundError\n\nSometimes when you're using PyPi, Conda, or virtual environments you can forget about the current version and location of Python and try to import packages in xonsh resulting in a `ModuleNotFoundError` error. Often this means you installed the package in another environment and didn't realise it. To avoid this read the section about xonsh installation above.\n\n### Intersection of console tools or shell syntax with Python builtins\n\nIn case of names or syntax intersection try to use aliases or [abbrevs](https://github.com/xonsh/xontrib-abbrevs) to resolve the conflict.\n\nThe case with `elepsis`:\n\n```xsh\naliases['...'] = 'cd ../..' # looks nice, but\n...\n# Elepsis\n\ndel aliases['...']\nabbrevs['...'] = 'cd ../..'\n... # becomes `cd ../..`\n```\n\nThe case with `import`:\n\n```xsh\ncd /tmp\n$PATH.append('/tmp')\necho 'echo I am import' > import && chmod +x import\n\nimport # Run subprocess `./import`\n# I am import\n\nimport args # Run Python import of `args` module\n# ModuleNotFoundError: No module named 'args'\n\naliases['imp'] = \"import\"\nimp\n# I am import\n```\n\n\n### Frozen terminal in interactive tools\n\nIf you run a console tool and get a frozen terminal (Ctrl+c, Ctrl+d is not working) this can be that the tool was interpreted as threaded and capturable program but the tool actually has interactive elements that expect the input from the user. There are four workarounds now:\n\n1. Disable [THREAD_SUBPROCS](https://xon.sh/envvars.html#thread-subprocs):\n\n ```python\n with ${...}.swap(THREAD_SUBPROCS=False):\n ./tool.sh\n ```\n\n2. Run the tool in uncaptured mode:\n\n ```python\n $[./tool.sh]\n ```\n\n3. Set the unthreadable predictor:\n\n ```python\n __xonsh__.commands_cache.threadable_predictors['tool.sh'] = lambda *a, **kw: False # use the pure name of the tool\n ./tool.sh\n ```\n\n4. Finally, check [`$XONSH_CAPTURE_ALWAYS`](https://xon.sh/envvars.html#xonsh-capture-always) value.\n\n### Uncaptured output\n\nIf you want to capture the output of a tool but it's not captured, there are three workarounds:\n\n1. Add the `head` or `cat` tool at the end of the pipeline to force using the threadable mode:\n\n ```python\n !(echo 123 | head -n 1000)\n #CommandPipeline(\n # returncode=0,\n # output='123\\n',\n # errors=None\n #)\n ```\n\n2. Change threading prediction for this tool:\n\n ```python\n __xonsh__.commands_cache.threadable_predictors['ssh'] = lambda *a, **kw: True\n\n !(ssh host -T \"echo 1\")\n #CommandPipeline(\n # returncode=0,\n # output='1\\n',\n # errors=None\n #)\n ```\n\n3. Wrap the tool into a bash subprocess:\n\n ```python\n !(bash -c \"echo 123\")\n #CommandPipeline(\n # returncode=0,\n # output='123\\n',\n # errors=None\n #)\n ```\n\n### [Bad file descriptor](https://github.com/xonsh/xonsh/issues/4224)\n\nUsing callable aliases in a long loop can cause the `Bad file descriptor` error to be raised. The workaround is to avoid using callable aliases in the loop and moving the code from callable alias directly into the loop or [marking the callable alias as unthreadable](https://xon.sh/tutorial.html#unthreadable-aliases):\n\n```python\nfrom xonsh.tools import unthreadable\n\n@unthreadable\ndef _e():\n execx('echo -n 1')\naliases['e'] = _e\n\nfor i in range(100):\n e\n```\n\n# Tips and tricks\n\n### Make your own installable xonsh RC file\n\nStart by forking [xontrib-rc-awesome](https://github.com/anki-code/xontrib-rc-awesome).\n\n### Triple quotes\n\nTo avoid escape character (i.e. `echo \"\\\"hello\\\"\"`) and make string more elegant use triple quotes:\n\n```xsh\necho \"\"\"{\"hello\":'world'}\"\"\"\n# {\"hello\":'world'}\n```\n\n### Python warlus operator in subprocess mode\n\n```xsh\necho Hello @(_name := input('Name: ')) # Use `_` to keep env clean.\necho Hello again @(_name)\n# Name: Mike\n# Hello Mike\n# Hello again Mike\n```\n\n### Using a text block in the command line\n\nThe first way is to use multiline strings:\n```xsh\necho @(\"\"\"\nline 1\nline 2\nline 3\n\"\"\".strip()) > file.txt\n\n$(cat file.txt)\n# 'line 1\\nline 2\\nline 3\\n'\n```\nThe second way is to use xonsh macro block via [xontrib-macro](https://github.com/anki-code/xontrib-macro):\n```xsh\nxpip install xontrib-macro\n\nfrom xontrib.macro.data import Write\n\nwith! Write('/tmp/t/hello.xsh', chmod=0o700, replace=True, makedir=True, verbose=True):\n echo world\n \n/tmp/t/hello.xsh\n# world\n```\n\nRun commands in docker:\n```python\ndocker run -it --rm xonsh/xonsh:slim xonsh -c @(\"\"\"\npip install --disable-pip-version-check -q lolcat\necho \"We're in docker container now!\" | lolcat\n\"\"\")\n```\nDon't forget that `Alt+Enter` can run the command from any place where cursor is.\n\n### Using the name of the alias in alias logic\n```xsh\n@aliases.register(\",\")\n@aliases.register(\",,\")\n@aliases.register(\",,,\")\n@aliases.register(\",,,,\")\ndef _superdot():\n cd @(\"../\" * len($__ALIAS_NAME))\n \n, # cd ../\n,, # cd ../../\n,,, # cd ../../../\n```\n\n### Python sugar: inline import\n\n```xsh\n# Run it or add to ~/.xonshrc\nimp = type('MyClass', (object,), {'__getattr__':lambda self, name: __import__(name) })()\n\n# Use `imp` as inline import sugar\nimp.json.loads('{\"a\":1}')\n# {'a': 1}\nimp.datetime.datetime.now().isoformat()\n# '2024-02-12T15:29:57.125696'\nimp.hashlib.md5(b'Hello world').hexdigest()\n# '3e25960a79dbc69b674cd4ec67a72c62'\n```\n\n### Ask to input argument and with autocomplete\n\nAsk simple input:\n```xsh\necho @(input('Text: '))\n# Text: hello\n# hello\n\necho Hello @(_name := input('Name: ')) # Use `_` to keep env clean.\necho Hello again @(_name)\n# Name: Mike\n# Hello Mike\n# Hello again Mike\n\n$ENV_NAME = input('Name: ') # Use input to set and reuse env variable\necho Name is $ENV_NAME\n# Name: Alex\n# Name is Alex\n```\n\nAsk input with completion:\n```xsh\nfrom prompt_toolkit import PromptSession\nfrom prompt_toolkit.completion import WordCompleter\n\ndef ask(arg : str, completions : list = []):\n completer = WordCompleter(completions)\n session = PromptSession(completer=completer)\n user_input = session.prompt(f'{arg}: ')\n return user_input\n\n\necho I am saying @(ask('What to say'))\n# What to say: hello\n# I am saying hello\n\necho Give @(ask('Fruit', ['apple', 'banana', 'orange'])) to @(ask('To', [$(whoami).strip()]))\n# Fruit: <Tab>\n# Fruit: apple\n# To: <Tab>\n# To: user\n# Give apple to user\n\n$MY_DIR = ask('Dir', $(ls /).splitlines())\n# Dir: <Tab> \n```\n\n### From the shell to REST API for one step\n\nIf you want to run shell commands from REST API you can create a [flask](https://flask.palletsprojects.com/) wrapper using [xontrib-macro](https://github.com/anki-code/xontrib-macro):\n```xsh\nxpip install flask xontrib-macro\n\ncd /tmp\n\nfrom xontrib.macro.data import Write\nwith! Write('myapi.xsh', chmod=0o700):\n import json\n from flask import Flask\n app = Flask(__name__)\n @app.route('/echo')\n def index():\n result = $(echo -n hello from echo) # run subprocess command\n return json.dumps({'result': result})\n app.run()\n\n./myapi.xsh\n# Running on http://127.0.0.1:5000\n\ncurl http://127.0.0.1:5000/echo\n# {\"result\": \"hello from echo\"}\n```\nDon't forget [about API security](https://flask-httpauth.readthedocs.io/en/latest/#basic-authentication-examples).\n\n### Interactively debugging a script\n\nIf you want to have a breakpoint to debug a script, use the standard Python [pdb](https://docs.python.org/3/library/pdb.html):\n\n```xsh\nxpip install xontrib-macro\nfrom xontrib.macro.data import Write\nwith! Write('/tmp/run.xsh', chmod=0o700, replace=True, makedir=True):\n echo hello\n $VAR = 1\n var = 2\n\n import pdb\n pdb.set_trace() # interactive debug\n\n echo finish\n\n\nxonsh /tmp/run.xsh\n# hello\n# > /tmp/run.xsh(9)<module>()\n# -> echo finish\n# (Pdb)\n\nvar\n# 2\n\n__xonsh__.env['VAR']\n# 1\n\nexit\n# bdb.BdbQuit\n```\n\n### Using xonsh wherever you go through the SSH\n\nYou've stuffed your command shell with aliases, tools, and colors but you lose it all when using ssh. The mission of the [xxh project](https://github.com/xxh/xxh) is to bring your favorite shell wherever you go through ssh without root access or system installations.\n\n### How to modify a command before execution?\n\nTo change the command between pressing enter and execution there is the [on_transform_command](https://xon.sh/events.html#on-transform-command) event:\n\n```python\nxpip install lolcat\n\n@events.on_transform_command\ndef _(cmd, **kw):\n if cmd.startswith('echo') and 'lolcat' not in cmd: \n # Be careful with the condition! The modified command will be passed \n # to `on_transform_command` event again and again until the event \n # returns the same command. Newbies can make a mistake here and\n # end up with unintended looping.\n return cmd.rstrip() + ' | lolcat'\n else:\n return cmd\n \necho 123456789 # <Enter>\n# Execution: echo 123456789 | lolcat\n```\n\n### Comma separated thousands in output (custom formatter)\n\nHere is a snippet from [@maxwellfire](https://github.com/maxwellfire):\n\n```xsh\n50000+50000\n# 100000\n\n500+500.123\n# 1000.123\n\nimport xonsh.pretty\nxonsh.pretty.for_type(type(1), lambda int, printer, cycle: printer.text(f'{int:,}'))\nxonsh.pretty.for_type(type(1.0), lambda float, printer, cycle: printer.text(f'{float:,}'))\n\n50000+50000\n# 100,000\n\n500+500.123\n# 1,000.123\n```\n\n### `chdir` [context manager](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) for scripting\n\n```xsh\nfrom xonsh.tools import chdir\n\ncd /tmp\nmkdir -p dir1\n\npwd\nwith chdir(\"./dir1\"):\n pwd\npwd\n\n# /tmp\n# /tmp/dir1\n# /tmp\n```\n\n### Juggling of exit code using python substitution\n\ncd-ing into directory and if count of files less then 100 run `ls`:\n\n```xsh\naliases['cdls'] = \"cd @($arg0) && @(lambda: 1 if len(g`./*`) > 100 else 0) && ls\"\ncdls / && pwd\n# bin dev etc ...\n# /\ncdls /usr/sbin && pwd\n# /usr/sbin\n```\n\n### How to paste and edit multiple lines of code while in interactive mode\n\nIn some terminals (Konsole in Linux or Windows Terminal for WSL) you can press `ctrl-x ctrl-e` to open up an editor (`nano` in Linux) in the terminal session, paste the code there, edit and then quit out. Your multiple line code will be pasted and executed.\n\n### Waiting for the job done\n```python\nsleep 100 & # job 1\nsleep 100 & # job 2\nsleep 100 & # job 3\n\nwhile $(jobs):\n time.sleep(1)\n\nprint('Job done!')\n```\n\n### How to trace xonsh code?\n\nTrace with [hunter](https://github.com/ionelmc/python-hunter):\n\n```python\npip install hunter\n$PYTHONHUNTER='depth_lt=10,stdlib=False' $XONSH_DEBUG=1 xonsh -c 'echo 1'\n```\n\nOr try [xunter](https://github.com/anki-code/xunter) for tracing and profiling.\n\n### From Bash to Xonsh\n\nRead [Bash to Xonsh Translation Guide](https://xon.sh/bash_to_xsh.html), run `bash -c! echo 123` or install [xontrib-sh](https://github.com/anki-code/xontrib-sh).\n\n### Xonsh and Windows\n\nFirst of all we recommend using [WSL 2](https://learn.microsoft.com/en-us/windows/wsl/about) with [Manjaro](https://github.com/sileshn/ManjaroWSL2) (that maintains a [rolling release](https://en.wikipedia.org/wiki/Rolling_release)) on Windows. Don't forget to [fix PATH](https://github.com/xonsh/xonsh/issues/3895#issuecomment-713078931).\n\nBut if you want to use xonsh in Windows environment:\n* Install [Windows Terminal](https://github.com/microsoft/terminal) - the modern terminal emulator for Windows.\n* Install [xontrib coreutils](https://xon.sh/api/_autosummary/xontribs/xontrib.coreutils.html#module-xontrib.coreutils), [cmdix](https://github.com/jaraco/cmdix), [pycoreutils](https://github.com/davidfischer/pycoreutils) - a pure Python implementation of the UNIX coreutils i.e. `echo`, `cat`, `pwd`,`ls`, etc.\n* Read [Windows-specific tips and tricks](https://xon.sh/platform-issues.html#windows).\n\n# Recipes\n\n### Using many profiles with AWS CLI and xonsh aliases\n\n```xsh\naws configure --profile p1\naws configure --profile p2\n\naliases['aws-p1'] = \"$AWS_DEFAULT_PROFILE='p1' @('aws') @($args)\"\naliases['aws-p2'] = \"$AWS_DEFAULT_PROFILE='p2' @('aws') @($args)\"\n\naws-p2 s3 ls s3://my-profile1-bucket/ # The same as `aws s3 ls --profile p2 s3://my-profile1-bucket/`\n```\n\n# Answers to the holy war questions\n\n### Bash is everywhere! Why xonsh?\n\nPython is everywhere as well ;)\n\n### Xonsh is slower! Why xonsh?\n\nYou can spend significantly more time Googling and debugging sh-based solutions as well as significantly more time to make the payload work after running a command. Yeah, xonsh is a bit slower but you will not notice that in real life tasks :)\n\nAlso take a look:\n\n* [Python 3.12: A Game-Changer in Performance and Efficiency](https://python.plainenglish.io/python-3-12-a-game-changer-in-performance-and-efficiency-8dfaaa1e744c)\n* [Python 3.11 is up to 10-60% faster than Python 3.10](https://docs.python.org/3.11/whatsnew/3.11.html)\n* [Making Python 5x FASTER with Guido van Rossum](https://www.youtube.com/watch?v=_r6bFhl6wR8).\n* [RustPython](https://github.com/RustPython/RustPython) ([performance](https://user-images.githubusercontent.com/1309177/212613257-5f4bca12-6d6b-4c79-9bac-51a4c6d08928.svg) of [Ruff](https://github.com/charliermarsh/ruff) - Python linter on Rust)\n\n### My fancy prompt in another shell is super duper! Why xonsh?\n\nThe fancy prompt is the tip of the iceberg. Xonsh shell brings other important features to love: [sane language](https://github.com/anki-code/xonsh-cheatsheet#basics), [powerful aliases](https://github.com/anki-code/xonsh-cheatsheet#aliases), [agile extensions](https://github.com/anki-code/xonsh-cheatsheet#xontrib---extension-or-plugin-for-xonsh), [history backends](https://github.com/anki-code/xonsh-cheatsheet#history), [fully customisable tab completion](https://github.com/anki-code/xonsh-cheatsheet#tab-completion), [magic macro blocks](https://github.com/anki-code/xonsh-cheatsheet#macro-block), [behaviour customisation via environment variables](https://xon.sh/envvars.html), and [more](https://github.com/anki-code/xonsh-cheatsheet#bind-hotkeys-in-prompt-toolkit-shell), and [more](https://github.com/anki-code/xonsh-cheatsheet#make-your-own-installable-xonsh-rc-file), and [more](https://github.com/anki-code/xonsh-cheatsheet#using-xonsh-wherever-you-go-through-the-ssh) :)\n\n### Xonsh has issues! Why xonsh?\n\nCompared to 15-20 year old shells, yeah, xonsh is a 5 year old youngster. But we've used it over these 5 years day by day to solve our tasks with success and happiness :)\n\n# Thank you!\n\nThank you for reading! This cheatsheet is the tip of the iceberg of the xonsh shell and you can find more in the [official documentation](https://xon.sh/contents.html#guides).\n\nAlso you can install the cheatsheet xontrib:\n```python\nxpip install xontrib-cheatsheet\nxontrib load cheatsheet\ncheatsheet\n# Opening: https://github.com/anki-code/xonsh-cheatsheet/blob/main/README.md\n```\n\nIf you like the cheatsheet, click \u2b50 on the repo and <a href=\"https://twitter.com/intent/tweet?text=The%20xonsh%20shell%20cheat%20sheet.&url=https://github.com/anki-code/xonsh-cheatsheet\" target=\"_blank\">tweet</a>.\n\n# Credits\n* [Xonsh Tutorial](https://xon.sh/tutorial.html)\n* Most copy-pastable examples prepared by [xontrib-hist-format](https://github.com/anki-code/xontrib-hist-format)\n* The cheat sheet xontrib was created with [xontrib cookiecutter template](https://github.com/xonsh/xontrib-cookiecutter).\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Cheat sheet for xonsh shell with copy-pastable examples.",
"version": "0.4.4",
"project_urls": {
"Code": "https://github.com/anki-code/xontrib-cheatsheet",
"Documentation": "https://github.com/anki-code/xontrib-cheatsheet/blob/master/README.md",
"Homepage": "https://github.com/anki-code/xontrib-cheatsheet",
"Issue tracker": "https://github.com/anki-code/xontrib-cheatsheet/issues"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "61505f869fd80a5beada83ac1f110d5e7ed1cc1c7f2531c53b66f0dbd793f5f2",
"md5": "6ecfed54f539b38ef05fc1e9dc68bb0a",
"sha256": "f6c0222db2518a8f934353a58d8dfb1630eca594dd4ae228f78a3da36e5afb1e"
},
"downloads": -1,
"filename": "xontrib_cheatsheet-0.4.4-py3-none-any.whl",
"has_sig": false,
"md5_digest": "6ecfed54f539b38ef05fc1e9dc68bb0a",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.6",
"size": 21826,
"upload_time": "2024-02-19T14:19:57",
"upload_time_iso_8601": "2024-02-19T14:19:57.618056Z",
"url": "https://files.pythonhosted.org/packages/61/50/5f869fd80a5beada83ac1f110d5e7ed1cc1c7f2531c53b66f0dbd793f5f2/xontrib_cheatsheet-0.4.4-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "338d897c20666a57731892eb7b63215dbc10d6a022effe0a36041ee717ecb5f0",
"md5": "02b1c1fc3e7b5d890059731ecc849fc7",
"sha256": "8128f3c3768496c08d12d50b68614a146b5a959786c9afe690d424ae347bafb6"
},
"downloads": -1,
"filename": "xontrib-cheatsheet-0.4.4.tar.gz",
"has_sig": false,
"md5_digest": "02b1c1fc3e7b5d890059731ecc849fc7",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.6",
"size": 59169,
"upload_time": "2024-02-19T14:19:59",
"upload_time_iso_8601": "2024-02-19T14:19:59.430886Z",
"url": "https://files.pythonhosted.org/packages/33/8d/897c20666a57731892eb7b63215dbc10d6a022effe0a36041ee717ecb5f0/xontrib-cheatsheet-0.4.4.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-02-19 14:19:59",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "anki-code",
"github_project": "xontrib-cheatsheet",
"github_not_found": true,
"lcname": "xontrib-cheatsheet"
}