{"id":13478080,"url":"https://github.com/anki-code/xonsh-cheatsheet","last_synced_at":"2025-12-31T01:04:41.281Z","repository":{"id":39896169,"uuid":"310804308","full_name":"anki-code/xonsh-cheatsheet","owner":"anki-code","description":"Cheat sheet for xonsh shell with copy-pastable examples. The best doc for the new users.","archived":false,"fork":false,"pushed_at":"2024-05-20T11:31:55.000Z","size":567,"stargazers_count":217,"open_issues_count":2,"forks_count":17,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-05-21T06:56:01.752Z","etag":null,"topics":["awesome","awesome-cheatsheet","cheat-sheet","cheat-sheets","cheatsheet","cheatsheets","console","data-science","devops","devops-scripts","hacking","shell","terminal","xonsh","xontrib"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/anki-code.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"custom":["https://github.com/anki-code","https://www.buymeacoffee.com/xxh","https://github.com/xonsh/xonsh#the-xonsh-shell-community"]}},"created_at":"2020-11-07T08:54:22.000Z","updated_at":"2024-06-01T07:37:50.528Z","dependencies_parsed_at":"2024-01-13T19:19:41.031Z","dependency_job_id":"c06816c4-0f6b-49b7-885a-534ee6f22b7a","html_url":"https://github.com/anki-code/xonsh-cheatsheet","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anki-code%2Fxonsh-cheatsheet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anki-code%2Fxonsh-cheatsheet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anki-code%2Fxonsh-cheatsheet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anki-code%2Fxonsh-cheatsheet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anki-code","download_url":"https://codeload.github.com/anki-code/xonsh-cheatsheet/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238590596,"owners_count":19497350,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["awesome","awesome-cheatsheet","cheat-sheet","cheat-sheets","cheatsheet","cheatsheets","console","data-science","devops","devops-scripts","hacking","shell","terminal","xonsh","xontrib"],"created_at":"2024-07-31T16:01:52.169Z","updated_at":"2025-12-31T01:04:41.267Z","avatar_url":"https://github.com/anki-code.png","language":"Python","readme":"\u003cp align=\"center\"\u003e\nCheat sheet for the \u003ca href=\"https://xon.sh\"\u003exonsh shell\u003c/a\u003e with copy-pastable examples. This is a good level of knowledge to start being productive.\n\u003cbr\u003e\u003cbr\u003e\n\u003cimg src=\"https://repository-images.githubusercontent.com/310804308/01f73a1d-3eaf-43a2-9aec-f9e92e28c78a\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\nIf you like the cheatsheet click ⭐ on the repo and \u003ca href=\"https://twitter.com/intent/tweet?text=The%20xonsh%20shell%20cheat%20sheet.\u0026url=https://github.com/anki-code/xonsh-cheatsheet\" target=\"_blank\"\u003etweet\u003c/a\u003e about it.\n\u003c/p\u003e\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. The xonsh shell is developed by a community of 300+ volunteers and the xonsh philosophy based on the principle of cooperation.\n\nIf you don't want to learn step by step jump to [demo examples](https://github.com/anki-code/xonsh-cheatsheet/blob/main/README.md#xonsh-basics).\n\n# What does xonsh mean?\n\nThe word \"xonsh\" comes from [conch](https://www.google.com/search?q=what+is+conch) - a common name of a number of different sea snails or shells (🐚, `@`). So \"xonsh\" is pronounced like \"consh\" ([kɑːnʃ]) which is a playful reference to the word \"shell\", often used to describe [command shells](https://en.wikipedia.org/wiki/Shell_(computing)). \"Consh\" is sometimes interpreted as \"console shell\".\n\nOver time the approach to replace a letter in the words to \"x\" and pronounce as short [`/k/`](https://dictionary.cambridge.org/pronunciation/english/k) when used with vowels (e.g. \"xat\" sounds like \"cat\" `[kæt]`) became the way to create unique names for xonsh related solutions e.g. [xontrib](https://xon.sh/tutorial_xontrib.html#overview), [xonfig](https://xon.sh/aliases.html#xonfig), [xunter](https://github.com/anki-code/xunter). Adding \"x\" in the beginning is also the way to create xonsh-related name e.g. [xpip](https://xon.sh/aliases.html#xpip).\n\nFun fact: when you run xonsh on *nix in the home directory the default prompt looks like `user@host ~ @` - it's a nice visual metaphor of snail (`~`) that lives in the conch (`@`) and the conch is the home for snail.\n\nYou can find more visuals around xonsh in [xonsh-logo](https://github.com/anki-code/xonsh-logo) repository.\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 xonsh container or the Linux AppImage to run and try xonsh.\n\n4. **[The best way to install xonsh as core shell](#the-best-way-to-install-xonsh-as-core-shell)**. You must read the previous sections before using this.\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\nOn any system you can install `python` and then install xonsh from pip i.e., `any_pkg_manager install python \u0026\u0026 python -m pip install 'xonsh[full]'`. This is the preferable way.\n\nIf you have `python` but no `pip` just install it using [`ensurepip`](https://docs.python.org/3/library/ensurepip.html):\n```xsh\npython -m ensurepip --upgrade\npip -V\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 (old version, maybe not full dependencies installed) but possible:\napt install xonsh     # Debian/Ubuntu\ndnf install xonsh     # Fedora\nbrew install xonsh    # OSX\npacman -S xonsh       # Arch Linux\n```\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 the current instance of xonsh. Use the [`xcontext`](https://xon.sh/aliases.html#xcontext) builtin alias to check the xonsh context.\n\nIn other words, you can activate a virtual environment during a xonsh session (using mamba, conda, [rye](https://github.com/xonsh/xonsh/discussions/5290), 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. Keep in mind current `$PATH` and as result `which xonsh` when running something.\n\nThus the second thing you should remember is that when you run xonsh in a 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 environment 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\n*Here is the real life example but mostly created for educational reasons. See the best way to install xonsh in the next section.*\n\nYou can use [Conda](https://docs.conda.io/en/latest/) (or faster replacement - [mamba](https://mamba.readthedocs.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\nxcontext  # xonsh \u003e= 0.22.0\n# [Current xonsh session]\n# xpython: /Users/username/miniconda3/bin/python  # `which xpython`: xonsh ran from `base` environment\n# xpip: /Users/username/miniconda3/bin/pip  # `which xpip`: pip from `base` environment from where xonsh ran\n#\n# [Current commands environment]\n# xonsh: /Users/username/miniconda3/bin/xonsh  # `which xonsh`: xonsh installed in `base` environment\n# python: /Users/username/miniconda3/bin/python # `which python`: `base` environment\n# pip: /Users/username/miniconda3/bin/pip  # `which pip`: `base` environment\n\nconda activate py310\n# Now the environment is `py310` but current xonsh session is still in `base` environment\n\nxcontext\n# [Current xonsh session]\n# xpython: /Users/username/miniconda3/bin/python  # `which xpython`: xonsh ran from `base` environment\n# xpip: /Users/username/miniconda3/bin/pip  # `which xpip`: pip from `base` environment from where xonsh ran\n#\n# [Current commands environment]\n# xonsh: /Users/username/miniconda3/envs/py310/bin/xonsh  # `which xonsh`: xonsh installed in `py310` environment\n# python: /Users/username/miniconda3/envs/py310/bin/python # `which python`: `py310` environment\n# pip: /Users/username/miniconda3/envs/py310/bin/pip  # `which pip`: `py310` environment\n\n# Run xonsh that installed in `py310` environment from xonsh session run in `base` environment\nxonsh\nconda activate py310\n# Now xonsh session is in `py310` environment and the current environment is also `py310`\n\nxcontext\n# [Current xonsh session]\n# xpython: /Users/username/miniconda3/envs/py310/bin/python  # `which xpython`: xonsh ran from `py310` environment\n# xpip: /Users/username/miniconda3/envs/py310/bin/pip  # `which xpip`: pip from `py310` environment from where xonsh ran\n#\n# [Current commands environment]\n# xonsh: /Users/username/miniconda3/envs/py310/bin/xonsh  # `which xonsh`: xonsh installed in `py310` environment\n# python: /Users/username/miniconda3/envs/py310/bin/python # `which python`: `py310` environment\n# pip: /Users/username/miniconda3/envs/py310/bin/pip  # `which pip`: `py310` environment\n\nimport ujson\n# No module named 'ujson'   # YES because ujson was installed in `base` environment\n```\n\nOn Mac we also recommend installing [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 -\u003e 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 for installing xonsh in case you need a 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#### The best way to install xonsh as core shell\n\nWhen xonsh becomes a core shell it's needed to keep python environment with xonsh stable, predictable and independent of any changes in the system. To forget about the cases where manipulations around python and packages break the shell unintended you can install xonsh with [`xonsh-install`](https://github.com/anki-code/xonsh-install/tree/main).\n\nNote! We do not recommend to use xonsh as a default login shell if you are not feel you strong and experienced. Because of most tools are waiting that login shell is POSIX-compliant you can face with issues when some tool is trying to run sh commands in xonsh.\n\n### Try xonsh without installation\n\n#### Container\n\nUsing open source Podman is recommended but docker also ok.\n\n```python\n# Container with specific Python version and latest release of xonsh\npodman run --rm -it python:3.11-slim /bin/bash \\\n -c \"pip install 'xonsh[full]' \u0026\u0026 xonsh\"\n\n# Container with specific Python version and xonsh from the master branch\npodman run --rm -it python:3.11-slim /bin/bash \\\n -c \"apt update \u0026\u0026 apt install -y git \u0026\u0026 pip install -U git+https://github.com/xonsh/xonsh \u0026\u0026 xonsh\"\n\n# Official xonsh container image may have an old version\npodman 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’t have Python on your host, you can access 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 a result, you can mix shell commands and Python code as easily as possible. Right off the bat examples:\n\n```xsh\ncd /tmp \u0026\u0026 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$CONCH='snail' ls                 # shell style setting env variable for command\n\nwith @.env.swap(CONCH='snail'):   # or using context manager\n    echo $CONCH\n\nwith p'/tmp/dir'.mkdir().cd():    # make directory\n    touch tmpfile.txt             # and operate inside\n\n$PATH.append('/tmp')              # PATH is list\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 info := $(podman info --format '{{json .}}'):\n    print('ContainersRunning:', json.loads(info)['ContainersRunning'])\n\n@.imp.json.loads($(echo '{\"a\":1}'))  # xonsh inline importer\n\nxpip install xontrib-dalias \u0026\u0026 xontrib load dalias\ny = $(@yaml dig +yaml google.com)  # convert output into object\ny[0]['message']['query_time']\n\npodman exec -it @($(@json podman ps --format json)['ID']) bash\n\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## Most frequent things that newcomers totally 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 novices 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. Use quotes to escape special characters, the special meaning of braces, or pass a string as an argument. When in doubt, use quotes!\n\nYou should clearly understand the difference:\n\n \u003ctable style=\"width:100%\"\u003e\n  \u003ctr\u003e\n    \u003cth\u003esh-lang shells\u003c/th\u003e\n    \u003cth\u003exonsh\u003c/th\u003e\n  \u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n1. Has an escape character:\n\u003cpre\u003e\n\u003cb\u003eecho 123\\ 456\u003c/b\u003e\n# 123 456\n\u003c/pre\u003e\n\u003c/td\u003e\n    \u003ctd\u003e\n1. Use quotes:\n\u003cpre\u003e\n\u003cb\u003eecho \"123 456\"\u003c/b\u003e\n# 123 456\n\u003c/pre\u003e\n\u003ca href=\"https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals\"\u003eEscape character\u003c/a\u003e to wrap and so on:\n\u003cpre\u003e\n\u003cb\u003eecho \"123\\\n456\"\u003c/b\u003e\n# 123456\n\u003c/pre\u003e\n\n\u003c/td\u003e\n  \u003c/tr\u003e\n\n\u003ctr\u003e\n\u003ctd\u003e\n2. Open the quotes:\n\u003cpre\u003e\n\u003cb\u003eecho --arg=\"val\"\u003c/b\u003e\n# --arg=val\u003cbr\u003e\n# and:\u003cbr\u003e\n\u003cb\u003eecho --arg \"val\"\u003c/b\u003e\n# --arg val\n\n\u003c/pre\u003e\n\u003c/td\u003e\n    \u003ctd\u003e\n2. Save quotes:\n\u003cpre\u003e\n\u003cb\u003eecho --arg=\"val\"\u003c/b\u003e\n# --arg=\"val\"\u003cbr\u003e\n# But if argument quoted entirely:\u003cbr\u003e\n\u003cb\u003eecho --arg \"val\"\u003c/b\u003e\n# --arg val\n\u003c/pre\u003e\n\u003c/td\u003e\n  \u003c/tr\u003e\n\n\u003ctr\u003e\n\u003ctd\u003e\n3. Brackets have no meaning:\n\u003cpre\u003e\n\u003cb\u003eecho {123} [456]\u003c/b\u003e\n# {123} [456]\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n\u003c/pre\u003e\n\u003c/td\u003e\n    \u003ctd\u003e\n3. Brackets have meaning:\n\u003cpre\u003e\n\u003cb\u003eecho {123} [456]\u003c/b\u003e\n# SyntaxError\u003cbr\u003e\n\u003cb\u003eecho \"{123}\" '[456]'\u003c/b\u003e\n# {123} [456]\n\u003c/pre\u003e\n\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e \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 @('args') @(['list', 'is']) $(echo here) \"and\" --say=\"hello\" to @([]) you\n    # ['echo', 'The', 'args', 'list', 'is', 'here', '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 is smarter (xonsh \u003e= 0.17.0):\n* Return the line if it's single line e.g. `$(whoami)` will return `'user'`.\n* Return [universal new lines](https://www.python.org/dev/peps/pep-0278/) for multiple lines e.g. `$(ls)` will return `'1\\n2\\n3\\n'`.\n* Finally you can use [xontrib-dalias](https://github.com/anki-code/xontrib-dalias) to have a list of lines e.g. `l = $(@lines cat file)`.\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 the output you can use python substitution e.g. use [splitlines](https://docs.python.org/3/library/stdtypes.html#str.splitlines):*\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\n### 4. Threading\n\nXonsh runs subprocess commands or callable aliases using threading prediction mechanism that simply called \"threading\" or \"(un)threadable\" words. This threading prediction was introduced to have an ability to capture any output from processes that are completely non interactive e.g. `echo` or `grep`. When you run `!(echo 1)` the `echo` process will be predicted as thredable and current terminal will be detached and stdout, stderr and everything will be captured. How to change the predicted threading value using `@thread` and `@unthread` aliases you can find below.\n\n# [Operators](https://xon.sh/tutorial.html#captured-subprocess-with-and)\n\n### Overview\n\nOperators:\n\n* `$()` is to run processes and capture the stdout. Almost the same as in traditional shells.\n\n* `!()` is to run sync or async threadable (capturable) processes. The terminal is detached for the process in this mode to deliver non-blocking behavior. To block the process and wait for result use `.end()`, `.out`, `.rtn` and other attributes that forces getting the result.\n\n* `![]` is to run processes without any capturing but return CommandPipeline with base info: pid, return code, timinig, etc. This operator is working when you run plain commands e.g. just `echo hello`.\n\n* `$[]` is to run processes without any capturing and any catching the result. Use it for uncapturable processes (e.g. `vim`) if you want to stream output directly to the terminal and without any capturing.\n\nExamples:\n\n```xsh\nid $(whoami)  # xonsh \u003e= 0.17.0\n\nworker1 = !(sleep 3)  # Non-blocking.\necho 'Something is happening while worker1 is working.'\nif worker1.rtn == 0:  # Blocking. The `.rtn` attribute call has `.end()` under the hood.\n    echo 'worker1 is done'\n# Note. There is issue with this case that will be fixed in xonsh \u003e 0.19.0.\n\nfile = p'~/.xonshrc'\nif ![ls @(file)]:\n    head @(file)\n\n$[vim ~/.xonshrc]\n```\n\nFrom tech side (most of the behavior is dictated by OS):\n\n| Operator           | Blocking | Capture stdout        | Capture stderr        | Attach TTY input | Attach TTY output      | Return                 |\n| ------------------ | -------- | --------------------- | --------------------- | ---------------- | ---------------------- | ---------------------- |\n| `$()`              | yes      | yes                   | no                    | yes              | no for threadable      | stdout                 |\n| `!()`              | no       | yes for threadable    | yes for threadable    | no               | no for threadable      | CommandPipeline        |\n| `![]`              | yes      | no                    | no                    | yes              | no for threadable      | HiddenCommandPipeline  |\n| `$[]`              | yes      | strict no             | no                    | yes              | yes                    | `None`                 |\n\nHere:\n* Threadable (capturable) process is the process without any interaction with user. Note that if unthreadable process will run with detached terminal it will be suspended by OS automatically.\n* Capturing \"strict no\" means that stream will be passed to the main terminal from any place of calling.\n\nNote:\n* If you want to run interactive xonsh from bash script you need to have interactive shebang (i.e. `#!/bin/bash -i`) to avoid suspending by OS.\n\n### `$()` - capture and return output without printing stdout and stderr\n\n*Technical name of this operator: captured stdout. Python call: `__xonsh__.subproc_captured_stdout()`.*\n\nCaptures stdout and returns single line or miltiline output with [universal new lines](https://www.python.org/dev/peps/pep-0278/):\n```python\n# xonsh \u003e= 0.17.0\n\n$(whoami)    # Python mode\n# 'user'\n\nid $(whoami)  # Subproc mode\n# uid=501(user) gid=20(staff)\n\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\nYou can change the behavior by setting `$XONSH_SUBPROC_OUTPUT_FORMAT` (xonsh \u003e= 0.17.0):\n\n```xsh\n$XONSH_SUBPROC_OUTPUT_FORMAT = 'list_lines'\n\n$(ls /)\n# ['/bin', '/etc', '/home']\n```\n\n### `!()` - capture all and return object without printing stdout and stderr\n\n*Technical name of this operator: captured object or full capturing with non blocking mode. Python call: `__xonsh__.subproc_captured_object()`*\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! This is non blocking operator: no waiting for enging output. To get the output you need to convert an object to a string, invoke [`.end()`](https://github.com/xonsh/xonsh/blob/6d58fb5bf7c62fa5c56721b62f40b214f83822eb/xonsh/procs/pipelines.py#L450-L459), ask for `.rtn` or use the `.out` to force ending the process and read output from internal buffers:\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\nNote! When you're using full capturing the stdout and stderr will be captured and there will be no terminal (tty) connected. You can use this operator only for non interactive tools running. If you will do `!(ls | fzf)` or `!(python -c \"input()\")` the executed command will be suspended by POSIX OS ([1](https://www.linusakesson.net/programming/tty/), [2](http://curiousthing.org/sigttin-sigttou-deep-dive-linux)) because the process is waiting for input in background. Use uncaptured operators for interactive tools and read the futher materials around unthreadable mode to do things right.\n\n### `$[]` - not capturing (return `None`), print stdout and stderr\n\n*Technical name of this operator: uncaptured mode. Python call: `__xonsh__.subproc_uncaptured()`.*\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### `![]` - print stdout/stderr and return hidden object\n\n*Technical name of this operator: uncaptured hidden object. Python call: `__xonsh__.subproc_captured_hiddenobject()`*\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 @.env.swap(XONSH_CAPTURE_ALWAYS=False):  # Default.\n    r = ![echo -e '1\\n2\\r3 4\\r\\n5']\n    # 1               # Stream output of the command\n    # 3 4\n    # 5\n    r               # No return value because it's HiddenCommandPipeline object\n    r.out           \n    # ''            # Empty because `$XONSH_CAPTURE_ALWAYS = False`.\n    r.returncode\n    # 0\n\nwith @.env.swap(XONSH_CAPTURE_ALWAYS=True):\n    r = ![echo -e '1\\n2\\r3 4\\r\\n5']\n    # 1               # Stream output of the command\n    # 3 4\n    # 5\n    r               # No return value because it's HiddenCommandPipeline object\n    r.out           # But it has the properties from CommandPipeline\n    # '1\\n2\\r3 4\\n5\\n'\n    r.returncode\n    # 0\n```\nElegant checking the result of the command using walrus operator:\n```xsh\nif r := ![ls NO]:\n    print(f'It works! Return code: {r.returncode}')\nelse:\n    print(f'It fails! Return code: {r.returncode}')\n\n# ls: cannot access 'NO': No such file or directory\n# It fails! Return code: 2\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*Technical name: captured inject output. API call: `__xonsh__.subproc_captured_inject()`*\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\nThree ways to get environment:\n```python\n# Get the list of environment variables\n@.env\n\n# Recommended for Python code and xontribs:\nfrom xonsh.built_ins import XSH  # Import current xonsh session.\nXSH.env  # Get the list of environment variables using xonsh session (XSH).\n```\nOperating with environment variables:\n```python\n$VAR = 'value'    # Set environment variable\n\nenv = @.env         # 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 env   # Check environment variable exists\n#True\n\nprint($VAR)\nwith @.env.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@.env.get('VAR', 'novalue')  # the way to get env variable with default value\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.append('/tmp')                             # Append path '/tmp' at end of $PATH list\n$PATH.prepend('/tmp')                            # (xonsh\u003e0.15.1) Insert path '/tmp' at front of $PATH list\n$PATH.insert(0, '/tmp')                          # Insert path '/tmp' to appropriate position of $PATH list\n$PATH.remove('/tmp')                             # Remove path '/tmp' (first match)\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```\nNote! Starting from xonsh 0.15.2 the logic was improved.\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\nEasy switch environment using alias:\n\n```xsh\naliases['lines'] = \"$XONSH_SUBPROC_OUTPUT_FORMAT = 'list_lines'; echo $XONSH_SUBPROC_OUTPUT_FORMAT\"\naliases['stream'] = \"$XONSH_SUBPROC_OUTPUT_FORMAT = 'stream_lines'; echo $XONSH_SUBPROC_OUTPUT_FORMAT\"\nlines\n# list_lines\n$(ls)\n# ['file1', 'file2', 'file3']\nstream\n# stream_lines\n$(ls)\n# 'file1\\nfile2\\nfile3\\n'\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## Function as an alias for group of commands\n\nOrdinarily \"alias\" word refers to a subprogram that has exit code and arguments for subprocess mode. In xonsh you can group commands and reuse it as Python functions or classes:\n\n```xsh\ndef hello(name):\n    echo hello @(name)\n\nhello('Alex')\n# hello Alex\n```\nor class:\n```xsh\nclass my:\n    @classmethod\n    def hello(cls, name):\n        echo hello @(name)\n\nmy.hello('Alex')\n# hello Alex\n```\n\n## Alias that returns command\n\nIf you need to transform command use `@aliases.return_command`:\n\n```xsh\n@aliases.register\n@aliases.return_command\ndef _xsudo(args):\n    \"\"\"Sudo with expanding aliases.\"\"\"\n    return ['sudo', '--', *aliases.eval_alias(args)]\n\naliases['install'] = \"apt install cowsay\"\nxsudo install\n# Password:\n# Install cowsay\n\n@aliases.register\n@aliases.return_command\ndef _vi(args):\n    \"\"\"Universal vi editor.\"\"\"\n    if $(which vim 2\u003e/dev/null):\n        return ['vim'] + args\n    else:\n        return ['vi'] + args\n\nvi /etc/hosts\n```\n\nNote! Using alias that returns command is much more preferable than callable alias if you need to just change the command. Callable alias is a complex process wrapper and in case of choice between return command alias and callable alias the right choice is the first one.\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    # print(args, file=stdout)  # Using stdout directly is the best practice to support pipes/tests/future.\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\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\nCapturing:\n\nCallable aliases tend to be capturable. Only the explicitly denoted uncaptured subprocess operator `$[]` is uncapturable, and the subprocess's stdout passes directly through xonsh to the screen.\n\n```xsh\n@aliases.register\ndef _hunter():\n    print('catch me')\n    echo if\n    $[echo you]\n    ![echo can]\nhunter\n# catch me\n# if\n# you\n# can\n$(hunter)\n# you\n# 'catch me\\nif\\ncan\\n'\n```\n\n*Calambur! The \"callable alias\" could be shortanized to \"callias\". The name Callias is primarily a gender-neutral name of Greek origin that means Beauty.*\n\n### Decorator Alias\n\nUsing `DecoratorAlias` and callable `output_format` you can create transformer:\n```xsh\nfrom xonsh.procs.specs import SpecAttrDecoratorAlias as dalias  # xonsh \u003e= 0.18.0\n\naliases['@noerr'] = dalias({\"raise_subproc_error\": False},\n                            \"Set `raise_subproc_error` to False.\")\naliases['@lines'] = dalias({\"output_format\": 'list_lines'},\n                            \"Set `list_lines` output format.\")\naliases['@json'] = dalias({\"output_format\": lambda lines: @.imp.json.loads('\\n'.join(lines))},\n                           \"Set `json` output format.\")\naliases['@path'] = dalias({\"output_format\": lambda lines: @.imp.pathlib.Path(':'.join(lines))},\n                           \"Set `path` output format.\")\naliases['@yaml'] = dalias({\"output_format\": lambda lines: @.imp.yaml.safe_load('\\n'.join(lines))},\n                           \"Set `yaml` output format.\")\n```\nNow you can:\n```xsh\n$(@lines ls /)\n# ['/bin', '/etc', '/home']\n\n$(@json echo '{\"a\":1}')  # Try with `curl` ;)\n# dict({\"a\":1})\n\n$(@path which xonsh)\n# Path('/path/to/xonsh')\n\n$(@path which xonsh).parent\n# Path('/path/to')\n\n\naliases['ydig'] = '@yaml dig +yaml'  # Update `dig` via `brew install bind` to have `+yaml`.\ny = $(ydig google.com)\ny[0]['type']\n# 'MESSAGE'\n\n\n$RAISE_SUBPROC_ERROR = True\nif ![@noerr ls nononofile]:  # Do not raise exception in case of error.\n    echo file \n```\nSee also [xontrib-dalias](https://github.com/anki-code/xontrib-dalias).\n\n## Abbrevs\n\nThere is [xontrib-abbrevs](https://github.com/xonsh/xontrib-abbrevs) as an 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 \u003cspace\u003e or \u003creturn\u003e 'gst' gets expanded to 'git status'.\n\nabbrevs['gp'] = \"git push \u003cedit\u003e --force\"  # Set the edit position.\nabbrevs['@'] = \"@(\u003cedit\u003e)\"  # 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 the current command buffer and the 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\nThe best description of how string literlas is working is [in the table from tutorial](https://xon.sh/tutorial.html#advanced-string-literals).\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, \u003cfunction __main__.m\u003e]\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```\nReal life example:\n```xsh\nfrom_json = lambda cmd: __import__(\"json\").loads(evalx(f\"$({cmd})\"))\no = from_json!(echo '{\"a\":1}')\no\n#{'a': 1}\ntype(o)\n# dict\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\npodman 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 Podman 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 Container(Block):\n    \"\"\"Run xonsh codeblock in a container.\"\"\"\n\n    def __init__(self):\n       self.image = 'xonsh/xonsh:slim'\n\n    def __exit__(self, *a, **kw):\n        $[podman run -it --rm @(self.image) /usr/local/bin/xonsh -c @(self.macro_block)]\n\n\nwith! Container() as d:\n   pip install lolcat\n   echo \"We're in the 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```xsh\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 \u003cNAME\u003e \u003cFUNC\u003e`\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-\u0026type=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 copy --trust gh:xonsh/xontrib-template .\n```\n\n### Xontrib as a bridge\n\nYou can integrate python tools into xonsh context and environment using xontrib e.g. see [fstrider](https://github.com/anki-code/fstrider/) [xontrib](https://github.com/anki-code/fstrider/?tab=readme-ov-file#xonsh-xontrib) where xontrib allows to inject xonsh context into file system navigation tool.\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 = ♥\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\u003cTab\u003e\n./host_lines.xsh --host \u003cTab\u003e\n./host_lines.xsh --host xon.sh\n# Count of lines on xon.sh: 568\n```\n\nTo make the interaction with scripts more awesome see also [xonsh-awesome-cli-app](https://github.com/anki-code/xonsh-awesome-cli-app) and articles around [click](https://click.palletsprojects.com/en/8.1.x/), [rich](https://github.com/Textualize/rich), [typer](https://typer.tiangolo.com/), etc.\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)\"\"\") \u003e /tmp/getpath.xsh\nchmod +x /tmp/getpath.xsh\n/tmp/getpath.xsh\n# This script is in /tmp\n```\n\n# Unit tests with xonsh and pytest\n\nStart here: [How do I write unit tests?](https://github.com/xonsh/xonsh/discussions/5303#discussioncomment-8786332).\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 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 -2\n# echo 123\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 \u003e 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### Shadowing of console tools or shell syntax with Python builtins\n\nIn case of name or syntax collision try to use aliases or [abbrevs](https://github.com/xonsh/xontrib-abbrevs) to resolve the conflict.\n\nThe case with `id` or `zip`:\n\n```xsh\nid\n# \u003cfunction id\u003e\nID\n# uid=501(user) gid=20(staff) groups=20(staff) ...\nzip\n# zip builtin\nZIP\n# zip [-options] [-b path] ...\nZip\n# zip [-options] [-b path] ...\n```\n\nThe case with `ellipsis`:\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' \u003e import \u0026\u0026 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### Uncaptured output\n\nIf you want to capture the output from a tool that basically interactive but has captured mode.\nFor example basically `ssh` return the remote terminal that should be unthredable and uncapturable.\nBut if you use it for getting the data from remote host you would like to capture it.\nThere are three workarounds:\n\n```xsh\n!(@thread ssh host -T \"echo 1\")  # Switch to thread (xonsh \u003e= 0.18.3).\n#CommandPipeline(returncode=0, output='1\\n')\n\n!(echo 123 | head)  # stream to captured\n#CommandPipeline(returncode=0, output='123\\n')\n\n!(bash -c \"echo 123\")  # wrap to capturable tool\n#CommandPipeline(returncode=0, output='123\\n')\n```\n\nHow to check the predictor result:\n\n```xsh\n__xonsh__.commands_cache.predict_threadable(['echo'])\n# True\n\n__xonsh__.commands_cache.predict_threadable(['ssh'])\n# False\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 a threaded and capturable program but the tool actually has interactive elements that expect input from the user. There are bunch of workarounds:\n\n```xsh\n@unthread ./tool.sh\n```\n```xsh\nwith @.env.swap(THREAD_SUBPROCS=False): $[./tool.sh]\n```\n```xsh\n$[./tool.sh]\n```\n\n### New python version\n\nBecause of xonsh syntax was based on Python syntax you can face with parser issues if you install the new Python version and run xonsh. Check that you're specifying certain version of Python when you're using xonsh in your projects and there is no situation when python can be updated witout testing.\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### Inline scripting\n\n#### Inline import\nUse `@.imp` as inline importer (xonsh \u003e= 0.18.2):\n\n```xsh\n@.imp.json.loads($(echo '{\"a\":1}'))\n# {'a': 1}\n@.imp.datetime.datetime.now().isoformat()\n# '2024-02-12T15:29:57.125696'\n@.imp.hashlib.md5(b'Hello world').hexdigest()\n# '3e25960a79dbc69b674cd4ec67a72c62'\n```\nDon't forget about autocompletion e.g. `@.imp.date\u003ctab\u003e`.\n\n#### Inline statements\n\nUse `$[]` to have inline statements:\n```xsh\nfor i in range(1,5): $[echo @(i)]\nif $(which vim): $[echo vim]\n$[echo vim] if $(which vim) else $[echo vi]\nwith @.env.swap(QWE=1): $[bash -c 'echo $QWE']\n$A=1 $B=2 bash -c 'echo $A $B'\n```\n\n### Triple quotes\n\nTo avoid escape characters (i.e. `echo \"\\\"hello\\\"\"`) and make strings more elegant use triple quotes:\n\n```xsh\necho \"\"\"{\"hello\":'world'}\"\"\"\n# {\"hello\":'world'}\n```\n\n### Python walrus operator in action\n\nUse in subprocess:\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\nUse with commands:\n\n```xsh\n(servers := $(@json echo '[\"srv1\", \"srv2\"]'))\n# list(['srv1', 'srv2'])\necho @(servers[0])\n# srv1\n```\n\n### Jump from aliases to CLI apps\n\nIf you realize that your alias becomes the app it's time to look at [xonsh-awesome-cli-app](https://github.com/anki-code/xonsh-awesome-cli-app).\n\n### Make interruption tolerant transactions\n\nWhen you have group of commands (transaction) it's good to use `DisableInterrupt` from [xontrib-macro](https://github.com/anki-code/xontrib-macro):\n\n```xsh\necho start\nwith! @.imp.xontrib.macro.signal.DisableInterrupt():\n    echo 'sleep start'\n    sleep 10\n    echo 'sleep end'\necho finish\n\n# start\n# sleep start\n# [Press Ctrl+C]\n# KeyboardInterrupt will be raised at the end of current transaction.\n# sleep end\n# Exception KeyboardInterrupt: KeyboardInterrupt was received during transaction.\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()) \u003e 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 a container:\n```python\npodman run -it --rm xonsh/xonsh:slim xonsh -c @(\"\"\"\npip install --disable-pip-version-check -q lolcat\necho \"We're in the podman container now!\" | lolcat\n\"\"\")\n```\nDon't forget that `Alt+Enter` can run the command from any place where the cursor is.\n\n### Use `prompt` instead of `input` for multiline input\n\nIn python there is `input` function but it has no support of multiline pasting. Use `prompt`:\n\n```xsh\nfrom prompt_toolkit import prompt\n\necho @(prompt('Content:\\n')) \u003e /tmp/myfile\n# Content:\n# \u003cPaste multiline text \"1\\n\\2\\n\" from clipboard\u003e\n\ncat /tmp/myfile\n# 1\n# 2\n```\nOne line version using inline importer (`@.imp`):\n```xsh\necho @(@.imp.prompt_toolkit.prompt(\"Content:\\n\")) \u003e /tmp/myfile\n```\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### Transparent callable environment variables\n\nFor example, you want to have the current timestamp in every command but instead of nesting like `@(dt())` you want sugar:\n\n```xsh\nclass TimestampCl:\n    def __repr__(self):\n        return str(@.imp.datetime.datetime.now().isoformat())\n\n$dt = TimestampCl()\n# or one-liner:\n# $dt = type('TimeCl', (object,), {'__repr__':lambda self: str(@.imp.datetime.datetime.now().isoformat()) })()\n\necho $dt\nsleep 1\necho $dt\n# 2024-03-05T23:34:50.188014\n# 2024-03-05T23:34:51.259861\n```\n\n### Use env context manager to keep command and namespace clean\n\nUsing AWS CLI to extract cost:\n```xsh\nwith @.env.swap(START=$(date -d \"30 days ago\" +%Y-%m-%d), END=$(date +%Y-%m-%d)):\n    aws ce get-cost-and-usage \\\n        --time-period 'Start=$START,End=$END' \\\n        --granularity DAILY \\\n        --metrics \"UnblendedCost\" \\\n        --group-by 'Type=DIMENSION,Key=SERVICE'\n```\n\nPostgreSQL connect with password input:\n```xsh\nwith @.env.swap(PGPASSWORD=@.imp.getpass.getpass('pgpass:')):\n    for db in ['db1', 'db2']:\n        psql postgresql://user@host:5439/@(db) -c 'select 1'\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# The way to have continuous interactive search.\nwhile 1: ![cat /etc/passwd | grep --color -i @(input('\\nUsername: '))]\nwhile 1: ![cat @(f:='/etc/passwd') | grep --color -i @(input(f+': '))]  # walrus happy\n```\n\nAsk for input with completion and history:\n```xsh\nfrom prompt_toolkit import PromptSession\nfrom prompt_toolkit.completion import WordCompleter\nfrom prompt_toolkit.history import FileHistory\n\ndef ask(title : str, completions : list = []):\n    filename = ''.join(c for c in title if c.isalpha())\n    history = FileHistory($XONSH_DATA_DIR + f'/ask_{filename}.txt')\n    completer = WordCompleter(completions)\n    session = PromptSession(completer=completer, history=history)\n    user_input = session.prompt(f'{title}: ')\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: \u003cTab\u003e\n# Fruit: apple\n# To: \u003cTab\u003e\n# To: user\n# Give apple to user\n\n$MY_DIR = ask('Dir', $(ls /).splitlines())\n# Dir: \u003cTab\u003e \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, request\n    app = Flask(__name__)\n    @app.route('/echo', methods=['GET'])\n    def index():\n        say = request.args.get('say')\n        result = $(echo -n @(say))  # run subprocess command\n        return json.dumps({'result': result})\n    app.run(host=\"127.0.0.1\", port=5000)  # debug=True\n\n./myapi.xsh\n# Running on http://127.0.0.1:5000\n\ncurl 'http://127.0.0.1:5000/echo?say=cow'\n# {\"result\": \"cow\"}\n```\nDon't forget [about API security](https://flask-httpauth.readthedocs.io/en/latest/#basic-authentication-examples).\n\n### Run pure xonsh engine\n\nBasically xonsh session loads RC files, inherit environment, uses dynamic colors, git callbacks in prompt, saves commands to history and more. Most of this features are disabled in not interactive mode (`xonsh -c 'echo 1'`). But in some cases you can want to rid of all features to reduce overhead on running completely. Here is the path: \n\n```xsh\nxonsh --no-rc --no-env --shell-type readline \\\n      -DCOLOR_INPUT=0 -DCOLOR_RESULTS=0 -DPROMPT='@ ' \\\n      -DXONSH_HISTORY_BACKEND=dummy -DXONTRIBS_AUTOLOAD_DISABLED=1\n```\nHere:\n* `--no-rc` to prevent loading RC files.\n* `--no-env` to prevent inheriting the environment.\n* `--shell-type readline` to use cheapest shell backend ([readline](https://docs.python.org/3/library/readline.html)).\n* `-DCOLOR_INPUT=0` to disable colors and file completer that can read files to choose the right color.\n* `-DCOLOR_RESULTS=0` to disable colors in output.\n* `-DPROMPT='@ '` to disable prompt with gitstatus and other complex fields.\n* `-DXONSH_HISTORY_BACKEND=dummy` to disable history backend.\n* `-DXONTRIBS_AUTOLOAD_DISABLED=1` to avoid loading xontribs.\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# \u003e /tmp/run.xsh(9)\u003cmodule\u003e()\n# -\u003e echo finish\n# (Pdb)\n\nvar\n# 2\n\n@.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 # \u003cEnter\u003e\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### Builtin change directory [context manager](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) for scripting\n\n```xsh\ncd /tmp\n\npwd\nwith p\"./a/b\".mkdir(mode=0o777, parents=True, exist_ok=True).cd():\n    pwd\npwd\n\n# /tmp\n# /tmp/a/b\n# /tmp\n```\n\n### Juggling of exit code using python substitution\n\ncd into a directory and, if the count of files is less then 100, run `ls`:\n\n```xsh\naliases['cdls'] = \"cd @($arg0) \u0026\u0026 @(lambda: 1 if len(g`./*`) \u003e 100 else 0) \u0026\u0026 ls\"\ncdls / \u0026\u0026 pwd\n# bin dev etc ...\n# /\ncdls /usr/sbin \u0026\u0026 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 \u0026  # job 1\nsleep 100 \u0026  # job 2\nsleep 100 \u0026  # job 3\n\nwhile $(jobs):\n    time.sleep(1)\n\nprint('Job done!')\n```\n\n### Do asynchronous task in interactive prompt\n\nFor example you can continuously [pulling history from other sessions](https://github.com/xonsh/xonsh/issues/1467#issuecomment-2180645180) or just run this in xonsh to print every second:\n\n```xsh\n$SHELL_TYPE\n# 'prompt_toolkit'\n\nimport asyncio\nfrom prompt_toolkit.shortcuts import print_formatted_text\n\nasync def print_and_sleep():\n    while True:\n        print_formatted_text('hey!')        \n        await asyncio.sleep(2)\n\nloop = asyncio.get_event_loop()\nloop.create_task(print_and_sleep())\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 a 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* [xonsh parser on Rust](https://github.com/jnoortheen/xonsh-rd-parser)\n* [Nuitka the Python Compiler](https://nuitka.net/) ([xonsh-binary](https://github.com/anki-code/xonsh-binary))\n* [`uv`](https://github.com/astral-sh/uv?tab=readme-ov-file#uv) and [`mamba`](https://mamba.readthedocs.io/en/latest/user_guide/micromamba.html) to install packages as fast as possible.\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), [macro commands and 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# Become a xonsh developer and contributor\n\nMoved to [xonsh-developer-toolkit](https://github.com/anki-code/xonsh-developer-toolkit).\n\n# Thank you!\n\nThank you for reading! This cheatsheet is just the tip of the iceberg of the xonsh shell; 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 ⭐ on the repo and \u003ca href=\"https://twitter.com/intent/tweet?text=The%20xonsh%20shell%20cheat%20sheet.\u0026url=https://github.com/anki-code/xonsh-cheatsheet\" target=\"_blank\"\u003etweet\u003c/a\u003e.\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 template](https://github.com/xonsh/xontrib-template).\n","funding_links":["https://github.com/anki-code","https://www.buymeacoffee.com/xxh","https://github.com/xonsh/xonsh#the-xonsh-shell-community"],"categories":["Python","See also"],"sub_categories":["pytest: xonsh not found"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanki-code%2Fxonsh-cheatsheet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanki-code%2Fxonsh-cheatsheet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanki-code%2Fxonsh-cheatsheet/lists"}