Skip to main content

Running Script Files

Execute a shell script by passing it as a positional argument:
nash script.sh
Nash reads the script from the host filesystem (not the VFS), parses it line-by-line, and executes each command in sequence.

Basic Script Example

Create a file hello.sh:
#!/usr/bin/env nash

echo "Starting script..."
mkdir -p /tmp/test
cd /tmp/test
echo "Hello from Nash!" > greeting.txt
cat greeting.txt
ls -l
Run it:
nash hello.sh
Output:
Starting script...
Hello from Nash!
-rw-r--r-- greeting.txt 18 bytes
Scripts execute inside Nash’s sandboxed VFS environment. They cannot access host files unless explicitly mounted with --bind.

Shebang Handling

Nash automatically ignores shebang lines (lines starting with #!) on line 1 of any script:
#!/usr/bin/env nash
echo "This works fine"
The shebang is skipped during execution. This means you can make scripts executable and run them directly:
chmod +x script.sh
./script.sh  # Still runs with nash if called with nash
Making scripts executable and running them with ./script.sh invokes the host shell interpreter specified in the shebang. To run with Nash, always use nash script.sh.

One-Shot Commands (-c)

Execute a single command string and exit using the -c flag:
nash -c "echo hello | grep hello"
Output:
hello
This is identical to bash’s -c behavior.

Complex One-Liners

You can use the full Nash syntax in -c mode:
nash -c "echo 'apple\nbanana\napple' | sort | uniq -c"

Quoting in -c Mode

Be mindful of shell quoting when using -c from bash:
nash -c 'echo $USER'           # Single quotes: Nash expands $USER
nash -c "echo \$USER"          # Escaped $: Nash expands $USER
nash -c "echo hello | grep hi" # Pipe preserved for Nash

Reading from Stdin (-s)

Use the -s flag to read commands from stdin line-by-line:
cat commands.txt | nash -s
or
nash -s < commands.txt

Example: Batch Processing

Create commands.txt:
mkdir -p /tmp/batch
echo "Processing file 1" > /tmp/batch/file1.txt
echo "Processing file 2" > /tmp/batch/file2.txt
ls /tmp/batch
cat /tmp/batch/file1.txt
Execute:
nash -s < commands.txt
Output:
file1.txt  file2.txt
Processing file 1

Heredoc Input

Combine -s with heredocs for inline script execution:
nash -s <<'EOF'
echo "Starting batch job"
mkdir -p /tmp/work
cd /tmp/work
echo "data" > input.txt
cat input.txt | grep data
EOF
When using -s, Nash reads stdin regardless of whether it’s a TTY. Combine with -i if you want interactive mode after stdin is exhausted (though this is rare).

Shell Flags for Scripts

Nash supports bash-compatible shell flags that modify script execution behavior:

Exit on Error (-e)

Stop execution immediately if any command returns non-zero:
nash -e script.sh
Example script.sh:
echo "Step 1"
false              # This fails
echo "Step 2"      # NEVER executed with -e
With -e:
nash -e script.sh
# Output:
# Step 1
# nash: errexit: command exited with status 1
Without -e:
nash script.sh
# Output:
# Step 1
# Step 2

Undefined Variable Errors (-u)

Treat references to unset variables as errors:
nash -u script.sh
Example:
echo "User: $USER"      # OK: $USER is set
echo "Missing: $FOOBAR" # ERROR with -u: FOOBAR not set

Trace Execution (-x)

Print each command to stderr before executing (set -x):
nash -x script.sh
Example script:
echo "hello"
mkdir /tmp/test
Output with -x:
+ echo "hello"
hello
+ mkdir /tmp/test

Verbose Input (-v)

Print each line as it’s read:
nash -v script.sh
This shows the raw input before any parsing or execution.

Combining Flags

Flags can be combined for robust script execution:
nash -eux script.sh  # errexit + nounset + xtrace
This is equivalent to the common bash pattern:
set -eux

Script Examples

Data Processing Pipeline

process.sh:
#!/usr/bin/env nash

# Generate sample data
echo "apple" > /tmp/fruits.txt
echo "banana" >> /tmp/fruits.txt
echo "apple" >> /tmp/fruits.txt
echo "cherry" >> /tmp/fruits.txt

# Process: sort, dedupe, count
cat /tmp/fruits.txt | sort | uniq -c

# Find specific items
grep "apple" /tmp/fruits.txt | wc -l
Run:
nash process.sh

Conditional Logic

check.sh:
test -f /etc/hostname && echo "Hostname file exists" || echo "Missing"
test -d /home/user && cd /home/user && pwd
test -z "$CUSTOM_VAR" && echo "CUSTOM_VAR is not set"
Run with environment override:
nash -E CUSTOM_VAR=value check.sh

Working with Host Files

analyze.sh:
#!/usr/bin/env nash

# Access host directory via mount
cd /data
find . -name "*.txt" -type f
cat report.txt | grep ERROR | wc -l
Run with mounted host directory:
nash --bind ./project-data:/data analyze.sh
Without a --bind mount, scripts cannot access host filesystem paths. The script will operate entirely within the VFS sandbox.

Script Error Handling

Parse Errors

If a line has invalid syntax, Nash reports the error and continues (unless -e is set):
echo "valid"
this is | bad syntax
echo "continues without -e"
Output:
valid
nash: parse error: unexpected token
continues without -e
With -e:
nash -e script.sh
# Output:
# valid
# nash: parse error: unexpected token
# nash: errexit: parse error

Exit Codes

Scripts return the exit code of the last executed command:
nash script.sh
echo $?  # Host shell exit code from nash

Advanced Usage

Login Shell Scripts

Combine -l with script execution to source rc files first:
nash -l script.sh
This sources /etc/profile and ~/.nashrc (from VFS) before running the script.

Custom RC with Script

nash --rcfile ./setup.nashrc script.sh

Environment Injection

Pass environment variables to scripts:
nash -E DEBUG=true -E API_URL=http://localhost script.sh
The script can access $DEBUG and $API_URL.

See Also

Build docs developers (and LLMs) love