Script Execution Methods

Understanding how to execute shell scripts is crucial for effective shell scripting. There are multiple ways to run scripts, each with its own use cases and implications.

Execution Methods Overview

Method Syntax New Process Environment Use Case
Direct ./script.sh Yes Inherited Most common
Interpreter bash script.sh Yes Inherited Testing/debugging
Source source script.sh No Modified Environment setup
Absolute Path /path/to/script.sh Yes Inherited System scripts

Method 1: Direct Execution

This is the most common way to run scripts.

Prerequisites

# Script must be executable
$ chmod +x myscript.sh

# Script must have proper shebang
$ head -1 myscript.sh
#!/bin/bash

Execution

# Run from current directory
$ ./myscript.sh

# Run from anywhere (if in PATH)
$ myscript.sh

Example Script

#!/bin/bash
# direct_example.sh
echo "Running in process: $$"
echo "Parent process: $PPID"
echo "Current directory: $(pwd)"
export NEW_VAR="Hello from script"

Test It

$ chmod +x direct_example.sh
$ ./direct_example.sh
Running in process: 12345
Parent process: 12344
Current directory: /home/user/scripts

# Check if NEW_VAR exists in current shell
$ echo $NEW_VAR
# (empty - variable doesn't exist in parent shell)

Method 2: Using Shell Interpreter

Run the script by explicitly calling the shell interpreter.

Bash Interpreter

$ bash myscript.sh

Other Interpreters

$ sh myscript.sh      # POSIX shell
$ zsh myscript.sh     # Z shell
$ dash myscript.sh    # Debian Almquist shell

Advantages

  • No execute permission needed
  • Override shebang: Force specific interpreter
  • Testing: Test script with different shells

Example

# Create script without execute permission
$ cat > test_interpreter.sh << 'EOF'
#!/bin/bash
echo "Shell: $0"
echo "Bash version: $BASH_VERSION"
EOF

# Run without making executable
$ bash test_interpreter.sh
Shell: bash
Bash version: 5.1.16(1)-release

# Try with different shell
$ sh test_interpreter.sh
Shell: sh
Bash version:

Method 3: Source (Dot) Command

Execute script in the current shell environment.

Syntax

$ source myscript.sh
# or
$ . myscript.sh

Key Characteristics

  • No new process: Runs in current shell
  • Environment changes persist: Variables and functions remain
  • No shebang needed: Uses current shell
  • No execute permission needed

Example Script

# source_example.sh
echo "Setting up environment..."
export PROJECT_ROOT="/home/user/myproject"
export PATH="$PROJECT_ROOT/bin:$PATH"

# Define a function
greet() {
    echo "Hello from sourced function!"
}

echo "Environment setup complete"
echo "PROJECT_ROOT: $PROJECT_ROOT"

Test Sourcing

# Before sourcing
$ echo $PROJECT_ROOT
# (empty)

# Source the script
$ source source_example.sh
Setting up environment...
Environment setup complete
PROJECT_ROOT: /home/user/myproject

# After sourcing - variables persist
$ echo $PROJECT_ROOT
/home/user/myproject

# Function is available
$ greet
Hello from sourced function!

Method 4: Absolute Path Execution

Run script using its full path.

Examples

# Full path execution
$ /home/user/scripts/myscript.sh

# Using $HOME variable
$ $HOME/scripts/myscript.sh

# Using tilde expansion
$ ~/scripts/myscript.sh

Use Cases

  • System scripts: /etc/init.d/apache2 start
  • Cron jobs: Full paths prevent PATH issues
  • Remote execution: SSH with full paths

Method 5: Command Substitution

Execute script and capture output.

Syntax

# Modern syntax
result=$(./myscript.sh)

# Legacy syntax (avoid)
result=`./myscript.sh`

Example

# Script that returns a value
$ cat > get_timestamp.sh << 'EOF'
#!/bin/bash
date +%Y%m%d_%H%M%S
EOF

$ chmod +x get_timestamp.sh

# Capture output
$ timestamp=$(./get_timestamp.sh)
$ echo "Backup file: backup_$timestamp.tar.gz"
Backup file: backup_20240115_143022.tar.gz

Execution Context and Environment

Process Creation

#!/bin/bash
# process_info.sh
echo "Script PID: $$"
echo "Parent PID: $PPID"
echo "Shell: $0"
ps -f --pid $$ --pid $PPID

Environment Inheritance

#!/bin/bash
# env_test.sh
echo "PATH: $PATH"
echo "HOME: $HOME"
echo "USER: $USER"
echo "Custom var: $MY_CUSTOM_VAR"

Test Environment

# Set a custom variable
$ export MY_CUSTOM_VAR="test value"

# Run script - inherits environment
$ ./env_test.sh
PATH: /usr/local/bin:/usr/bin:/bin
HOME: /home/user
USER: user
Custom var: test value

Script Arguments and Parameters

Passing Arguments

$ ./myscript.sh arg1 arg2 arg3

Accessing Arguments

#!/bin/bash
# args_example.sh
echo "Script name: $0"
echo "First argument: $1"
echo "Second argument: $2"
echo "All arguments: $@"
echo "Number of arguments: $#"

Test Arguments

$ ./args_example.sh hello world 123
Script name: ./args_example.sh
First argument: hello
Second argument: world
All arguments: hello world 123
Number of arguments: 3

Exit Status and Error Handling

Exit Status

#!/bin/bash
# exit_status.sh
echo "Performing operation..."

# Simulate success or failure
if [ "$1" = "fail" ]; then
    echo "Operation failed!"
    exit 1
else
    echo "Operation successful!"
    exit 0
fi

Check Exit Status

$ ./exit_status.sh success
Operation successful!
$ echo $?
0

$ ./exit_status.sh fail
Operation failed!
$ echo $?
1

Advanced Execution Techniques

Background Execution

# Run script in background
$ ./long_running_script.sh &
[1] 12345

# Check background jobs
$ jobs
[1]+  Running    ./long_running_script.sh &

Conditional Execution

# Run second command only if first succeeds
$ ./script1.sh && ./script2.sh

# Run second command only if first fails
$ ./script1.sh || ./script2.sh

# Always run second command
$ ./script1.sh; ./script2.sh

Piping Script Output

# Pipe script output to another command
$ ./generate_data.sh | sort | uniq

# Redirect output to file
$ ./report_script.sh > report.txt 2>&1

Debugging Script Execution

Debug Mode

# Show commands as they execute
$ bash -x myscript.sh

# Or add to script
#!/bin/bash -x

Verbose Mode

# Show input lines as they're read
$ bash -v myscript.sh

Syntax Check

# Check syntax without executing
$ bash -n myscript.sh

Combined Options

# Multiple debug options
$ bash -xv myscript.sh

Security Considerations

File Permissions

# Secure script permissions
$ chmod 755 myscript.sh  # Owner: rwx, Others: r-x
$ chmod 700 myscript.sh  # Owner only: rwx

PATH Security

#!/bin/bash
# Use absolute paths for security
/bin/ls /home/user
/usr/bin/whoami

Input Validation

#!/bin/bash
# Validate input before execution
if [ $# -ne 1 ]; then
    echo "Usage: $0 <filename>"
    exit 1
fi

filename="$1"
if [ ! -f "$filename" ]; then
    echo "Error: File '$filename' not found"
    exit 1
fi

Best Practices

1. Always Use Shebang

#!/bin/bash
# or
#!/usr/bin/env bash  # More portable

2. Set Error Handling

#!/bin/bash
set -euo pipefail  # Exit on error, undefined vars, pipe failures

3. Use Appropriate Execution Method

  • Direct execution: General purpose scripts
  • Source: Environment setup scripts
  • Interpreter: Testing and debugging
  • Background: Long-running processes

4. Handle Arguments Properly

#!/bin/bash
if [ $# -eq 0 ]; then
    echo "Usage: $0 <arguments>"
    exit 1
fi

5. Provide Clear Output

#!/bin/bash
echo "Starting process..."
# ... script logic ...
echo "Process completed successfully"

Understanding these execution methods gives you the flexibility to run scripts in the most appropriate way for your specific needs and environment.