Python-powered shell providing superset of Python with shell primitives for cross-platform command execution and automation.
Xonsh provides comprehensive directory navigation and management capabilities through the dirstack module. This includes traditional shell commands like cd, pushd, popd, and dirs, along with context managers for temporary directory changes.
from xonsh.dirstack import cd, pushd_fn, popd_fn, dirs_fn, DIRSTACK
def cd(args: list[str], stdin=None) -> None:
"""Change current directory.
Parameters
----------
args : list[str]
Directory arguments. First argument is target directory.
Supports special directories:
- '-': Previous directory
- '~': Home directory
- No args: Home directory
stdin : optional
Standard input (unused)
Examples
--------
cd(['/tmp']) # Change to /tmp
cd(['-']) # Change to previous directory
cd(['~']) # Change to home directory
cd([]) # Change to home directory
"""
def pushd_fn(args: list[str], stdin=None) -> None:
"""Push directory onto stack and change to it.
Parameters
----------
args : list[str]
Directory arguments or stack operations:
- Directory path: Push and change to directory
- '+N': Rotate stack bringing Nth entry to top
- '-N': Rotate stack bringing Nth entry from bottom to top
- No args: Swap top two directories
stdin : optional
Standard input (unused)
Examples
--------
pushd_fn(['/tmp']) # Push /tmp and change to it
pushd_fn(['+2']) # Rotate stack, bring 2nd entry to top
pushd_fn([]) # Swap top two directories
"""
def popd_fn(args: list[str], stdin=None) -> None:
"""Pop directory from stack and change to it.
Parameters
----------
args : list[str]
Stack operation arguments:
- '+N': Remove Nth entry from stack
- '-N': Remove Nth entry from bottom
- No args: Pop top directory and change to it
stdin : optional
Standard input (unused)
Examples
--------
popd_fn([]) # Pop top directory
popd_fn(['+1']) # Remove 1st entry from stack
popd_fn(['-0']) # Remove bottom entry from stack
"""
def dirs_fn(args: list[str], stdin=None) -> None:
"""Display directory stack.
Parameters
----------
args : list[str]
Display options:
- '-c': Clear directory stack
- '-p': Print one directory per line
- '-v': Print with line numbers
- '-l': Use full pathnames
- '+N': Display Nth entry
- '-N': Display Nth entry from bottom
stdin : optional
Standard input (unused)
Examples
--------
dirs_fn([]) # Show directory stack
dirs_fn(['-p']) # Show one per line
dirs_fn(['-v']) # Show with line numbers
dirs_fn(['-c']) # Clear directory stack
"""
# Global directory stack
DIRSTACK: list[str] # Current directory stackfrom xonsh.dirstack import with_pushd
def with_pushd(dirname: str):
"""Context manager for temporary directory changes.
Parameters
----------
dirname : str
Directory to change to temporarily
Returns
-------
context manager
Context manager that changes to dirname and restores on exit
Examples
--------
with with_pushd('/tmp'):
# Working in /tmp
print(os.getcwd()) # /tmp
# Back to original directory
"""
# Alias available in API module
from xonsh.api.os import indir
# indir is an alias to with_pushdfrom xonsh.dirstack import DIRSTACK
# Direct stack access
current_stack = DIRSTACK.copy() # Get current stack
stack_size = len(DIRSTACK) # Stack depth
top_dir = DIRSTACK[0] if DIRSTACK else None # Top directory
# Stack operations through built-in functions
from xonsh.built_ins import XSH
# Access through shell session
if XSH.shell:
# Execute directory commands
XSH.execer.eval("cd /tmp")
XSH.execer.eval("pushd /var")
XSH.execer.eval("popd")
XSH.execer.eval("dirs")from xonsh.tools import expand_path, ON_WINDOWS
def expand_path(path: str) -> str:
"""Expand user home directory and environment variables in path.
Parameters
----------
path : str
Path with potential ~ or $VAR expansions
Returns
-------
str
Fully expanded absolute path
Examples
--------
expand_path('~/Documents') # /home/user/Documents
expand_path('$HOME/file.txt') # /home/user/file.txt
"""
# Platform-specific directory handling
if ON_WINDOWS:
# Windows-specific path handling
pass
else:
# Unix-like path handling
passfrom xonsh.events import events
@events.on_chdir
def directory_changed(olddir: str, newdir: str) -> None:
"""Called when directory changes.
Parameters
----------
olddir : str
Previous directory
newdir : str
New current directory
"""
print(f"Changed from {olddir} to {newdir}")
# Directory change detection
import os
def monitor_directory_changes():
"""Monitor and respond to directory changes."""
current_dir = os.getcwd()
# Register directory change handler
@events.on_chdir
def log_dir_change(old, new):
with open('/tmp/dir_changes.log', 'a') as f:
f.write(f"Directory changed: {old} -> {new}\n")# Interactive directory navigation
"""
In xonsh shell:
>>> cd /tmp
>>> pushd /var/log
>>> pushd /etc
>>> dirs -v # Show numbered stack
>>> popd # Back to /var/log
>>> popd # Back to /tmp
>>> cd - # Back to original directory
"""
# Programmatic directory operations
from xonsh.built_ins import XSH
def navigate_project_dirs():
"""Navigate through common project directories."""
dirs = ['/src', '/tests', '/docs', '/config']
for directory in dirs:
XSH.execer.eval(f"pushd {directory}")
# Do work in directory
XSH.execer.eval("popd")import os
from xonsh.api.os import indir
def process_directories(dir_list: list[str]):
"""Process files in multiple directories."""
results = []
for directory in dir_list:
with indir(directory):
# Work in specific directory
files = os.listdir('.')
results.append((directory, len(files)))
return results
# Temporary directory operations
def backup_and_modify(target_dir: str):
"""Backup directory and make modifications."""
backup_dir = f"{target_dir}.backup"
# Create backup
with indir(os.path.dirname(target_dir)):
os.system(f"cp -r {os.path.basename(target_dir)} {backup_dir}")
# Make modifications in original
with indir(target_dir):
# Modify files in target directory
passfrom xonsh.built_ins import XSH
# Configure directory stack behavior
env = XSH.env
env['CDPATH'] = '/home/user:/opt:/usr/local' # Search path for cd
env['AUTO_CD'] = True # Auto-cd to directory names
env['AUTO_PUSHD'] = True # Auto-pushd on cd
env['PUSHD_SILENT'] = False # Show directory after pushd
env['PUSHD_MINUS'] = False # Use +N instead of -N for pushdThe directory management system provides powerful navigation capabilities that integrate seamlessly with both interactive shell usage and programmatic Python operations.
Install with Tessl CLI
npx tessl i tessl/pypi-xonsh