Skip to main content
Nash scripts look and behave like bash scripts but run in a fully sandboxed environment. Scripts can use variables, conditionals, loops, and all Nash built-in commands.

Basic Script Structure

Nash scripts are plain text files with commands:
hello.sh
#!/usr/bin/env nash

echo "Hello, World!"
echo "Current directory: $(pwd)"
echo "User: $USER"
Run the script:
user@nash:/home/user$ nash hello.sh
Hello, World!
Current directory: /home/user
User: user
Shebangs like #!/usr/bin/env nash are ignored in Nash but help document script intent.

Using Variables

Variables are set without $ and accessed with $:
variables.sh
#!/usr/bin/env nash

# Set variables using export
export NAME="Alice"
export VERSION="1.0.0"
export PROJECT_DIR="/home/user/projects"

# Access variables
echo "Project: $NAME"
echo "Version: $VERSION"
echo "Location: $PROJECT_DIR"

# Command substitution
export CURRENT_TIME=$(echo "2024-03-15")
export FILE_COUNT=$(ls | wc -l)

echo "Time: $CURRENT_TIME"
echo "Files: $FILE_COUNT"
Output:
Project: Alice
Version: 1.0.0
Location: /home/user/projects
Time: 2024-03-15
Files: 5

Conditionals with Test

The test command (or [) evaluates conditions:
conditionals.sh
#!/usr/bin/env nash

export CONFIG_FILE="config.json"

# Test if file exists
test -f $CONFIG_FILE && echo "Config found" || echo "Config missing"

# Test if directory exists
test -d /home/user && echo "Home directory exists"

# String comparison
export ENV="production"
test "$ENV" = "production" && echo "Running in production mode"

# Numeric comparison
export PORT=8080
test $PORT -eq 8080 && echo "Using default port"

Test Operators

OperatorDescription
-fFile exists and is regular file
-dDirectory exists
-ePath exists (file or directory)

Error Handling

Use the -e flag to exit immediately on error:
error_handling.sh
#!/usr/bin/env nash -e

echo "Starting process..."

# Create required directory
mkdir -p /home/user/output
test -d /home/user/output || exit 1

echo "Directory ready"

# Create output file
touch /home/user/output/result.txt
test -f /home/user/output/result.txt && echo "File created" || exit 1

echo "Process completed successfully"
Run with error checking:
user@nash:/home/user$ nash -e error_handling.sh
Starting process...
Directory ready
File created
Process completed successfully
The -e flag (errexit) makes scripts fail fast when any command returns a non-zero exit code. Use it for production scripts.

Complete Script Examples

Example 1: Project Setup Script

setup_project.sh
#!/usr/bin/env nash -e

export PROJECT_NAME="my-app"
export PROJECT_DIR="/home/user/projects/$PROJECT_NAME"

echo "Setting up project: $PROJECT_NAME"

# Create project structure
mkdir -p $PROJECT_DIR
cd $PROJECT_DIR

mkdir -p src tests docs config
echo "Created directory structure"

# Create initial files
touch README.md
echo "# $PROJECT_NAME" > README.md
echo "" >> README.md
echo "A new project" >> README.md

touch src/main.js
echo "// Main application file" > src/main.js

touch tests/main.test.js
echo "// Test file" > tests/main.test.js

touch config/settings.json
echo '{"version": "1.0.0"}' > config/settings.json

# Create .gitignore
touch .gitignore
echo "node_modules/" > .gitignore
echo "dist/" >> .gitignore
echo ".env" >> .gitignore

echo "Created initial files"

# Display structure
tree $PROJECT_DIR

echo "Project setup complete!"
Run the script:
user@nash:/home/user$ nash setup_project.sh
Setting up project: my-app
Created directory structure
Created initial files
/home/user/projects/my-app
├── .gitignore
├── README.md
├── config/
   └── settings.json
├── docs/
├── src/
   └── main.js
└── tests/
    └── main.test.js

4 directories, 5 files
Project setup complete!

Example 2: Log Analysis Script

analyze_logs.sh
#!/usr/bin/env nash

export LOG_FILE="/home/user/access.log"
export OUTPUT_DIR="/home/user/reports"

echo "Analyzing logs: $LOG_FILE"

# Create output directory
mkdir -p $OUTPUT_DIR

# Check if log file exists
test -f $LOG_FILE || {
  echo "Error: Log file not found"
  exit 1
}

# Count total requests
export TOTAL=$(cat $LOG_FILE | wc -l)
echo "Total requests: $TOTAL"

# Extract GET requests
cat $LOG_FILE | grep "GET" > $OUTPUT_DIR/get_requests.txt
export GET_COUNT=$(cat $OUTPUT_DIR/get_requests.txt | wc -l)
echo "GET requests: $GET_COUNT"

# Extract POST requests
cat $LOG_FILE | grep "POST" > $OUTPUT_DIR/post_requests.txt
export POST_COUNT=$(cat $OUTPUT_DIR/post_requests.txt | wc -l)
echo "POST requests: $POST_COUNT"

# Find unique IPs
cat $LOG_FILE | cut -d' ' -f1 | sort | uniq > $OUTPUT_DIR/unique_ips.txt
export UNIQUE_IPS=$(cat $OUTPUT_DIR/unique_ips.txt | wc -l)
echo "Unique IPs: $UNIQUE_IPS"

# Top IPs
cat $LOG_FILE | cut -d' ' -f1 | sort | uniq -c | sort -r > $OUTPUT_DIR/top_ips.txt
echo "Top IPs saved to $OUTPUT_DIR/top_ips.txt"

# Create summary
echo "=== Log Analysis Summary ===" > $OUTPUT_DIR/summary.txt
echo "Total Requests: $TOTAL" >> $OUTPUT_DIR/summary.txt
echo "GET Requests: $GET_COUNT" >> $OUTPUT_DIR/summary.txt
echo "POST Requests: $POST_COUNT" >> $OUTPUT_DIR/summary.txt
echo "Unique IPs: $UNIQUE_IPS" >> $OUTPUT_DIR/summary.txt

echo "Analysis complete! Results in $OUTPUT_DIR"
cat $OUTPUT_DIR/summary.txt

Example 3: Backup Script

backup.sh
#!/usr/bin/env nash -e

export SOURCE_DIR="/home/user/projects"
export BACKUP_DIR="/home/user/backups"
export TIMESTAMP=$(echo "2024-03-15-120000")
export BACKUP_NAME="backup-$TIMESTAMP"

echo "Starting backup process..."
echo "Source: $SOURCE_DIR"
echo "Destination: $BACKUP_DIR/$BACKUP_NAME"

# Verify source exists
test -d $SOURCE_DIR || {
  echo "Error: Source directory not found"
  exit 1
}

# Create backup directory
mkdir -p $BACKUP_DIR/$BACKUP_NAME

# Create backup metadata
touch $BACKUP_DIR/$BACKUP_NAME/metadata.txt
echo "Backup created: $TIMESTAMP" > $BACKUP_DIR/$BACKUP_NAME/metadata.txt
echo "Source: $SOURCE_DIR" >> $BACKUP_DIR/$BACKUP_NAME/metadata.txt
echo "Files:" >> $BACKUP_DIR/$BACKUP_NAME/metadata.txt

# Find and list all files
find $SOURCE_DIR -type f > /home/user/file_list.txt
export FILE_COUNT=$(cat /home/user/file_list.txt | wc -l)
cat /home/user/file_list.txt >> $BACKUP_DIR/$BACKUP_NAME/metadata.txt

echo "Found $FILE_COUNT files"

# Copy files (simplified - normally would preserve structure)
mkdir -p $BACKUP_DIR/$BACKUP_NAME/files

echo "Backup completed successfully"
echo "Backup location: $BACKUP_DIR/$BACKUP_NAME"
echo "Total files: $FILE_COUNT"

ls -l $BACKUP_DIR/$BACKUP_NAME/

Example 4: Data Processing Pipeline

process_data.sh
#!/usr/bin/env nash -e

export INPUT_FILE="/home/user/raw_data.csv"
export OUTPUT_DIR="/home/user/processed"

echo "Data Processing Pipeline"
echo "========================"

# Setup
mkdir -p $OUTPUT_DIR
test -f $INPUT_FILE || {
  echo "Creating sample data..."
  touch $INPUT_FILE
  echo "id,name,value,status" > $INPUT_FILE
  echo "1,Alice,100,active" >> $INPUT_FILE
  echo "2,Bob,200,inactive" >> $INPUT_FILE
  echo "3,Charlie,150,active" >> $INPUT_FILE
  echo "4,Diana,300,active" >> $INPUT_FILE
  echo "5,Eve,50,inactive" >> $INPUT_FILE
}

echo "Step 1: Filtering active records"
cat $INPUT_FILE | grep "active" > $OUTPUT_DIR/active.csv
export ACTIVE_COUNT=$(cat $OUTPUT_DIR/active.csv | wc -l)
echo "  Found $ACTIVE_COUNT active records"

echo "Step 2: Extracting names"
cat $OUTPUT_DIR/active.csv | cut -d',' -f2 > $OUTPUT_DIR/names.txt
echo "  Saved to $OUTPUT_DIR/names.txt"

echo "Step 3: Extracting values"
cat $OUTPUT_DIR/active.csv | cut -d',' -f3 > $OUTPUT_DIR/values.txt
echo "  Saved to $OUTPUT_DIR/values.txt"

echo "Step 4: Creating summary"
touch $OUTPUT_DIR/summary.txt
echo "Data Processing Summary" > $OUTPUT_DIR/summary.txt
echo "======================" >> $OUTPUT_DIR/summary.txt
echo "" >> $OUTPUT_DIR/summary.txt
echo "Active Records: $ACTIVE_COUNT" >> $OUTPUT_DIR/summary.txt
echo "" >> $OUTPUT_DIR/summary.txt
echo "Active Users:" >> $OUTPUT_DIR/summary.txt
cat $OUTPUT_DIR/names.txt >> $OUTPUT_DIR/summary.txt

echo "" >> $OUTPUT_DIR/summary.txt
echo "Processing complete!"

cat $OUTPUT_DIR/summary.txt

Example 5: Environment Configuration

configure_env.sh
#!/usr/bin/env nash

export ENV_TYPE=$1

# Default to development if not specified
test -z "$ENV_TYPE" && export ENV_TYPE="development"

echo "Configuring environment: $ENV_TYPE"

# Set common variables
export APP_NAME="myapp"
export VERSION="1.0.0"

# Environment-specific settings
test "$ENV_TYPE" = "production" && {
  export DEBUG="false"
  export LOG_LEVEL="error"
  export PORT=80
  echo "Production configuration loaded"
}

test "$ENV_TYPE" = "development" && {
  export DEBUG="true"
  export LOG_LEVEL="debug"
  export PORT=3000
  echo "Development configuration loaded"
}

test "$ENV_TYPE" = "staging" && {
  export DEBUG="false"
  export LOG_LEVEL="info"
  export PORT=8080
  echo "Staging configuration loaded"
}

# Create .env file
touch .env
echo "APP_NAME=$APP_NAME" > .env
echo "VERSION=$VERSION" >> .env
echo "ENV=$ENV_TYPE" >> .env
echo "DEBUG=$DEBUG" >> .env
echo "LOG_LEVEL=$LOG_LEVEL" >> .env
echo "PORT=$PORT" >> .env

echo ""
echo "Configuration file created:"
cat .env

echo ""
echo "Environment ready!"
Run with different environments:
user@nash:/home/user$ nash configure_env.sh production
Configuring environment: production
Production configuration loaded

Configuration file created:
APP_NAME=myapp
VERSION=1.0.0
ENV=production
DEBUG=false
LOG_LEVEL=error
PORT=80

Environment ready!

Script Best Practices

1

Use -e for error handling

Add -e to the shebang to exit on errors:
#!/usr/bin/env nash -e
2

Validate inputs

Check that required files and directories exist:
test -f $INPUT_FILE || exit 1
test -d $OUTPUT_DIR || mkdir -p $OUTPUT_DIR
3

Use descriptive variable names

export PROJECT_NAME="myapp"  # Good
export PN="myapp"            # Bad
4

Add comments and echo progress

# Process data files
echo "Processing data..."
cat data.csv | grep active > results.txt
echo "Processing complete"
5

Clean up temporary files

# Create temp file
touch /tmp/temp_data.txt

# ... do work ...

# Clean up
rm /tmp/temp_data.txt

Shell Flags

Nash supports bash-compatible flags:
FlagDescriptionUsage
-eExit on errornash -e script.sh
-uError on unset variablesnash -u script.sh
-xPrint commands before executionnash -x script.sh
-vPrint lines as they are readnash -v script.sh
Combine flags for better debugging: nash -ex script.sh runs with both error-exit and command-trace enabled.

Running Scripts

nash script.sh

Build docs developers (and LLMs) love