Shell and Terminal Configuration
Advanced shell configuration for the local execution environment, including shell detection, customization, and terminal interaction.
Shell Detectionβ
Automatic Detectionβ
The local adapter automatically detects the appropriate shell based on your platform:
import { $ } from '@xec-sh/core';
// Platform-based detection
const result = await $`echo $0`;
// Linux/macOS: /bin/sh, /bin/bash, or /bin/zsh
// Windows: cmd.exe or powershell.exe
Detection Priorityβ
The adapter uses the following priority for shell detection:
// Unix-like systems priority
const unixShells = [
'/bin/bash', // Preferred
'/bin/sh', // Fallback
'/usr/bin/bash', // Alternative locations
'/usr/bin/sh'
];
// Windows systems priority
const windowsShells = [
'cmd.exe', // Default
'powershell.exe' // If available
];
Runtime Detectionβ
Check which shell is being used:
// Get current shell
const shell = await $`echo $SHELL || echo %COMSPEC%`;
console.log('Current shell:', shell.stdout.trim());
// Detect shell type
const isBasher = await $.with({ throwOnNonZeroExit: false })`[[ -n "$BASH_VERSION" ]]`;
const isZsh = await $.with({ throwOnNonZeroExit: false })`[[ -n "$ZSH_VERSION" ]]`;
const isFish = await $.with({ throwOnNonZeroExit: false })`echo $FISH_VERSION`;
if (isBasher.exitCode === 0) {
console.log('Running in Bash');
} else if (isZsh.exitCode === 0) {
console.log('Running in Zsh');
} else if (isFish.stdout) {
console.log('Running in Fish');
}
Shell Profiles and RC Filesβ
Loading Shell Profilesβ
Control which initialization files are loaded:
// Load interactive shell with full profile
await $.with({
shell: '/bin/bash -i'
})`alias`; // Shows all aliases
// Load specific profile
await $.with({
shell: '/bin/bash',
env: {
BASH_ENV: '~/.bashrc'
}
})`source ~/.bash_profile && echo $MY_CUSTOM_VAR`;
// Skip profile loading (faster)
await $.with({
shell: '/bin/sh'
})`echo "Fast execution without profiles"`;
Custom RC Filesβ
Use custom initialization files:
// Create temporary RC file
const customRc = `
export PS1='> '
alias ll='ls -la'
function greet() { echo "Hello, $1!"; }
`;
await $`echo '${customRc}' > /tmp/custom.rc`;
// Use custom RC
await $.with({
shell: '/bin/bash',
env: {
BASH_ENV: '/tmp/custom.rc'
}
})`greet World`; // Output: Hello, World!
Shell Options and Modesβ
Bash Optionsβ
Configure Bash behavior with options:
// Strict mode
await $.with({ shell: '/bin/bash' })`
set -euo pipefail # Exit on error, undefined vars, pipe failures
IFS=$'\\n\\t' # Set Internal Field Separator
# Your commands here
echo "Running in strict mode"
`;
// Debug mode
await $.with({ shell: '/bin/bash' })`
set -x # Print commands before execution
VAR="test"
echo $VAR
set +x # Disable debug mode
`;
// Nounset mode
await $.with({ shell: '/bin/bash' })`
set -u # Error on undefined variables
echo ${UNDEFINED_VAR:-"default value"}
`;
Zsh Optionsβ
Configure Zsh-specific features:
// Zsh with extended globbing
await $.with({ shell: '/bin/zsh' })`
setopt EXTENDED_GLOB
echo **/*.js # Recursive glob
`;
// Zsh with history expansion disabled
await $.with({ shell: '/bin/zsh' })`
setopt NO_BANG_HIST
echo "No history expansion!"
`;
// Zsh with null glob
await $.with({ shell: '/bin/zsh' })`
setopt NULL_GLOB
files=(*.nonexistent)
echo "Files: \${files[@]}" # No error if no matches
`;
Fish Shell Optionsβ
Configure Fish shell features:
// Fish with custom functions
await $.with({ shell: '/usr/bin/fish' })`
function greet
echo "Hello, $argv!"
end
greet "Fish User"
`;
// Fish with abbreviations
await $.with({ shell: '/usr/bin/fish' })`
abbr -a g git
abbr -a ga 'git add'
abbr -a gc 'git commit'
`;
Interactive vs Non-Interactive Shellsβ
Non-Interactive Mode (Default)β
Standard execution without terminal interaction:
// Non-interactive (default)
const result = await $`echo "Simple output"`;
console.log(result.stdout); // "Simple output\n"
// Explicitly non-interactive
await $.with({
shell: '/bin/bash'
})`echo "No terminal required"`;
Interactive Modeβ
Enable terminal interaction when needed:
// Interactive shell with TTY
await $.with({
shell: '/bin/bash -i',
stdio: 'inherit' // Inherit parent's stdio
})`read -p "Enter your name: " name && echo "Hello, $name"`;
// Interactive with custom TTY settings
const proc = $.with({
shell: '/bin/bash -i',
env: {
TERM: 'xterm-256color',
COLUMNS: '120',
LINES: '40'
}
})`top`;
// Kill after 5 seconds
setTimeout(() => proc.kill(), 5000);
Terminal Emulationβ
TTY Allocationβ
Control pseudo-terminal allocation:
// Allocate PTY for color output
const result = await $.with({
env: {
TERM: 'xterm-256color',
FORCE_COLOR: '1'
}
})`ls --color=always`;
// Check if TTY is available
const hasTTY = await $`test -t 0 && echo "TTY available" || echo "No TTY"`;
console.log(hasTTY.stdout);
ANSI Color Supportβ
Handle colored terminal output:
// Force color output
await $.with({
env: {
CLICOLOR: '1',
CLICOLOR_FORCE: '1',
FORCE_COLOR: '1',
NO_COLOR: '' // Remove NO_COLOR if set
}
})`npm test`;
// Strip ANSI codes if needed
import { stripAnsi } from '@xec-sh/core/utils';
const colored = await $`ls --color=always`;
const plain = stripAnsi(colored.stdout);
console.log('Plain output:', plain);
Terminal Sizeβ
Set terminal dimensions:
// Set specific terminal size
await $.with({
env: {
COLUMNS: '80',
LINES: '24'
}
})`tput cols && tput lines`;
// Get current terminal size
const size = await $`
echo "Columns: $(tput cols)"
echo "Lines: $(tput lines)"
`;
console.log(size.stdout);
Shell Functions and Aliasesβ
Defining Functionsβ
Create and use shell functions:
// Bash functions
await $.with({ shell: '/bin/bash' })`
# Define function
function deploy() {
local env=$1
echo "Deploying to $env environment"
# deployment logic here
}
# Use function
deploy production
`;
// Zsh functions with advanced features
await $.with({ shell: '/bin/zsh' })`
function backup() {
local source=\${1:?Source required}
local dest=\${2:-/backup}
echo "Backing up $source to $dest"
cp -r "$source" "$dest"
}
backup /data /backup/data
`;
Using Aliasesβ
Work with shell aliases:
// Load and use aliases
await $.with({ shell: '/bin/bash -i' })`
# Define aliases
alias ll='ls -la'
alias gs='git status'
alias dc='docker-compose'
# Use aliases
ll /tmp
`;
// Check available aliases
const aliases = await $.with({ shell: '/bin/bash -i' })`alias`;
console.log('Available aliases:', aliases.stdout);
Environment Customizationβ
PATH Managementβ
Customize command search paths:
// Prepend to PATH
await $.with({
env: {
PATH: `/custom/bin:${process.env.PATH}`
}
})`which custom-command`;
// Append to PATH
await $.with({
env: {
PATH: `${process.env.PATH}:/opt/tools/bin`
}
})`tool --version`;
// Complete PATH replacement
await $.with({
env: {
PATH: '/usr/bin:/bin' // Minimal PATH
}
})`ls /`;
Locale Settingsβ
Configure locale and language settings:
// Set UTF-8 locale
await $.with({
env: {
LANG: 'en_US.UTF-8',
LC_ALL: 'en_US.UTF-8',
LC_CTYPE: 'en_US.UTF-8'
}
})`echo "Unicode: δ½ ε₯½δΈη π"`;
// Different locale for dates
await $.with({
env: {
LC_TIME: 'de_DE.UTF-8'
}
})`date`;
Prompt Customizationβ
Customize shell prompts:
// Bash prompt
await $.with({
shell: '/bin/bash -i',
env: {
PS1: '\\u@\\h:\\w\\$ ', // user@host:path$
PS2: '> ', // Continuation prompt
PS4: '+ ' // Debug prompt
}
})`echo "Custom prompt"`;
// Zsh prompt with colors
await $.with({
shell: '/bin/zsh -i',
env: {
PROMPT: '%F{green}%n@%m%f:%F{blue}%~%f$ '
}
})`pwd`;
Shell Integrationβ
Command Historyβ
Manage shell command history:
// Use history file
await $.with({
shell: '/bin/bash',
env: {
HISTFILE: '~/.custom_history',
HISTSIZE: '10000',
HISTCONTROL: 'ignoredups:erasedups'
}
})`history | tail -10`;
// Disable history
await $.with({
shell: '/bin/bash',
env: {
HISTFILE: '/dev/null'
}
})`sensitive-command`;
Job Controlβ
Manage background jobs:
// Run job in background
await $.with({ shell: '/bin/bash' })`
sleep 10 &
JOB_PID=$!
echo "Started job with PID: $JOB_PID"
# Wait for job
wait $JOB_PID
echo "Job completed"
`;
// List jobs
await $.with({ shell: '/bin/bash -i' })`
sleep 100 &
sleep 200 &
jobs -l
`;
PowerShell Configuration (Windows)β
Execution Policyβ
Configure PowerShell execution policies:
// Set execution policy for session
await $.with({ shell: 'powershell.exe' })`
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process
./script.ps1
`;
// Check current policy
const policy = await $.with({ shell: 'powershell.exe' })`
Get-ExecutionPolicy
`;
console.log('Execution policy:', policy.stdout.trim());
PowerShell Profilesβ
Load PowerShell profiles:
// Load specific profile
await $.with({
shell: 'powershell.exe',
env: {
PSModulePath: 'C:\\CustomModules'
}
})`
. $PROFILE
Get-Module
`;
// Skip profiles (faster)
await $.with({ shell: 'powershell.exe -NoProfile' })`
Write-Host "Fast execution"
`;
Performance Optimizationβ
Shell Selection for Performanceβ
Choose the right shell for your needs:
// Fastest: sh (minimal features)
const fast = await $.with({ shell: '/bin/sh' })`echo "Fast"`;
// Balanced: bash (good features, reasonable speed)
const balanced = await $.with({ shell: '/bin/bash' })`echo "Balanced"`;
// Feature-rich: zsh (many features, slower startup)
const featured = await $.with({ shell: '/bin/zsh' })`echo "Featured"`;
// Benchmark shell startup
const shells = ['/bin/sh', '/bin/bash', '/bin/zsh'];
for (const shell of shells) {
const start = Date.now();
await $.with({ shell })`true`;
console.log(`${shell}: ${Date.now() - start}ms`);
}
Optimize Shell Startupβ
Reduce shell initialization time:
// Skip RC files
await $.with({
shell: '/bin/bash --norc'
})`echo "Fast startup"`;
// Minimal environment
await $.with({
shell: '/bin/sh',
env: {
PATH: '/usr/bin:/bin',
HOME: '/tmp'
}
})`command`;
// Direct execution (no shell)
await $.with({
shell: false
})`/usr/bin/echo "Fastest - no shell overhead"`;
Troubleshooting Shell Issuesβ
Debug Shell Executionβ
Enable debugging to troubleshoot issues:
// Bash debug mode
await $.with({ shell: '/bin/bash -x' })`
VAR="test"
echo $VAR
`; // Shows: + VAR=test \n + echo test
// Verbose mode
await $.with({ shell: '/bin/bash -v' })`
echo "Verbose"
`; // Shows commands as read
// Combined debugging
await $.with({ shell: '/bin/bash -xv' })`
complex-script
`;
Common Shell Problemsβ
Quoting Issuesβ
// Problem: Spaces in arguments
const file = "my file.txt";
// await $`cat ${file}`; // Error: tries to cat "my" and "file.txt"
// Solution: Proper quoting
await $`cat "${file}"`;
// Or use array form
await $.with({ shell: false })`cat ${file}`;
Variable Expansionβ
// Problem: Variable not expanding
await $`echo '$HOME'`; // Output: $HOME
// Solution: Use double quotes
await $`echo "$HOME"`; // Output: /home/user
Path Issuesβ
// Problem: Command not found
try {
await $`custom-tool`;
} catch (error) {
// Solution: Check PATH
const path = await $`echo $PATH`;
console.log('Current PATH:', path.stdout);
// Add to PATH if needed
await $.with({
env: {
PATH: `${process.env.PATH}:/usr/local/bin`
}
})`custom-tool`;
}
Next Stepsβ
- Debugging Techniques - Debug shell command execution
- Local Setup - Basic local environment configuration
- SSH Environment - Remote shell execution
- Performance Guide - Optimize shell performance