Shell Script Arguments: Complete Guide
Overview
Shell script arguments are command-line parameters passed to a script when it is executed. These arguments allow scripts to be flexible and reusable by accepting input data from the user or other programs. Arguments are essential for creating dynamic scripts that can process different data sets or perform various operations based on user input.
Table of Contents
1. [Basic Concepts](#basic-concepts) 2. [Positional Parameters](#positional-parameters) 3. [Special Variables](#special-variables) 4. [Argument Processing Techniques](#argument-processing-techniques) 5. [Advanced Argument Handling](#advanced-argument-handling) 6. [Error Handling](#error-handling) 7. [Best Practices](#best-practices) 8. [Examples and Use Cases](#examples-and-use-cases)
Basic Concepts
When a shell script is executed, any additional words on the command line become arguments to the script. These arguments are automatically assigned to special variables that can be accessed within the script.
Syntax
`bash
./script_name.sh argument1 argument2 argument3 ...
`
The shell automatically parses the command line and assigns each space-separated word to numbered variables starting from $1.
Positional Parameters
Positional parameters are the primary mechanism for accessing command-line arguments in shell scripts. They are referenced using the dollar sign followed by a number.
Basic Positional Parameters
| Parameter | Description |
|-----------|-------------|
| $0 | The name of the script itself |
| $1 | The first argument |
| $2 | The second argument |
| $3 | The third argument |
| $n | The nth argument (where n > 9, use ${n}) |
Example Script: basic_args.sh
`bash
#!/bin/bash
Basic argument demonstration
echo "Script name: $0" echo "First argument: $1" echo "Second argument: $2" echo "Third argument: $3"`Execution:
`bash
chmod +x basic_args.sh
./basic_args.sh hello world 123
`
Output:
`
Script name: ./basic_args.sh
First argument: hello
Second argument: world
Third argument: 123
`
Accessing Arguments Beyond $9
For arguments beyond the ninth position, use curly braces:
`bash
#!/bin/bash
echo "Tenth argument: ${10}"
echo "Eleventh argument: ${11}"
`
Special Variables
Shell scripts provide several special variables for working with arguments:
Complete Special Variables Table
| Variable | Description | Example Usage |
|----------|-------------|---------------|
| $# | Number of arguments passed | if [ $# -eq 0 ]; then echo "No arguments"; fi |
| $@ | All arguments as separate words | for arg in "$@"; do echo $arg; done |
| $ | All arguments as a single word | echo "All args: $" |
| $ | Process ID of current script | echo "PID: $" |
| $? | Exit status of last command | command; if [ $? -eq 0 ]; then echo "Success"; fi |
| $! | Process ID of last background command | command &; echo "Background PID: $!" |
Detailed Explanation of $@ vs $*
The difference between $@ and $* becomes important when dealing with quoted arguments:
`bash
#!/bin/bash
echo "Using \$@:" for arg in "$@"; do echo " [$arg]" done
echo "Using \$*:"
for arg in "$*"; do
echo " [$arg]"
done
`
Execution:
`bash
./script.sh "hello world" "foo bar"
`
Output:
`
Using $@:
[hello world]
[foo bar]
Using $*:
[hello world foo bar]
`
Argument Processing Techniques
Basic Validation
Always validate the number and type of arguments:
`bash
#!/bin/bash
Check if correct number of arguments provided
if [ $# -ne 2 ]; then echo "Usage: $0source_file="$1" dest_file="$2"
Check if source file exists
if [ ! -f "$source_file" ]; then echo "Error: Source file '$source_file' does not exist" exit 1 fiecho "Copying $source_file to $dest_file"
cp "$source_file" "$dest_file"
`
Processing All Arguments
`bash
#!/bin/bash
echo "Processing $# arguments:"
Method 1: Using $@
for arg in "$@"; do echo "Processing: $arg" doneMethod 2: Using while loop and shift
while [ $# -gt 0 ]; do echo "Current argument: $1" shift # Move to next argument done`The shift Command
The shift command moves positional parameters to the left:
| Command | Effect |
|---------|--------|
| shift | $2 becomes $1, $3 becomes $2, etc. |
| shift 2 | Shifts by 2 positions |
| shift n | Shifts by n positions |
`bash
#!/bin/bash
echo "Before shift: $1 $2 $3"
shift
echo "After shift: $1 $2 $3"
shift 2
echo "After shift 2: $1 $2 $3"
`
Advanced Argument Handling
Option Processing with getopts
The getopts command provides a standardized way to process command-line options:
`bash
#!/bin/bash
Default values
verbose=false output_file="" input_file=""Process options
while getopts "vo:i:h" opt; do case $opt in v) verbose=true ;; o) output_file="$OPTARG" ;; i) input_file="$OPTARG" ;; h) echo "Usage: $0 [-v] [-o output_file] [-i input_file]" echo " -v: Verbose mode" echo " -o: Output file" echo " -i: Input file" echo " -h: Show this help" exit 0 ;; \?) echo "Invalid option: -$OPTARG" >&2 exit 1 ;; :) echo "Option -$OPTARG requires an argument." >&2 exit 1 ;; esac doneShift past processed options
shift $((OPTIND-1))Remaining arguments are in $@
echo "Verbose: $verbose" echo "Output file: $output_file" echo "Input file: $input_file" echo "Remaining arguments: $@"`getopts Variables and Options
| Variable | Description |
|----------|-------------|
| OPTARG | Contains the argument for options that require one |
| OPTIND | Index of the next argument to process |
| opt | Current option being processed |
| Option String | Meaning |
|---------------|---------|
| "abc" | Options -a, -b, -c (no arguments) |
| "a:b:c" | Option -a and -b require arguments, -c doesn't |
| ":abc" | Silent mode (custom error handling) |
Long Options Processing
For long options (--option), you need custom processing:
`bash
#!/bin/bash
while [[ $# -gt 0 ]]; do
case $1 in
--verbose|-v)
verbose=true
shift
;;
--output|-o)
output_file="$2"
shift 2
;;
--input|-i)
input_file="$2"
shift 2
;;
--help|-h)
echo "Usage: $0 [OPTIONS]"
echo "Options:"
echo " --verbose, -v Enable verbose mode"
echo " --output, -o Specify output file"
echo " --input, -i Specify input file"
echo " --help, -h Show this help"
exit 0
;;
-*)
echo "Unknown option: $1" >&2
exit 1
;;
*)
# Positional argument
positional_args+=("$1")
shift
;;
esac
done
`
Error Handling
Comprehensive Error Checking
`bash
#!/bin/bash
Function to display usage
usage() { echo "Usage: $0Function to check if file exists
check_file() { if [ ! -f "$1" ]; then echo "Error: File '$1' does not exist" >&2 exit 1 fi }Check minimum arguments
if [ $# -lt 2 ]; then echo "Error: Insufficient arguments" >&2 usage ficommand="$1" shift
Validate command
case "$command" in copy|move|delete) ;; *) echo "Error: Invalid command '$command'" >&2 usage ;; esacProcess files
for file in "$@"; do check_file "$file" echo "Processing $file with command $command" done`Exit Codes Table
| Exit Code | Meaning | |-----------|---------| | 0 | Success | | 1 | General error | | 2 | Misuse of shell command | | 126 | Command invoked cannot execute | | 127 | Command not found | | 128+n | Fatal error signal "n" |
Best Practices
Input Validation and Security
`bash
#!/bin/bash
Always quote variables to handle spaces
safe_copy() { local source="$1" local dest="$2" # Validate input if [ -z "$source" ] || [ -z "$dest" ]; then echo "Error: Both source and destination required" >&2 return 1 fi # Check for dangerous characters if [[ "$dest" =~ [;&|] ]]; then echo "Error: Invalid characters in destination" >&2 return 1 fi cp "$source" "$dest" }Use arrays for multiple arguments
declare -a files while [[ $# -gt 0 ]]; do files+=("$1") shift doneProcess array
for file in "${files[@]}"; do echo "Processing: $file" done`Documentation and Help
`bash
#!/bin/bash
Script: file_processor.sh
Description: Process files with various operations
Author: Your Name
Version: 1.0
show_help() { cat << EOF NAME file_processor.sh - Process files with various operations
SYNOPSIS $0 [OPTIONS] COMMAND FILE...
DESCRIPTION This script processes files with the specified command.
OPTIONS -v, --verbose Enable verbose output -h, --help Show this help message -o, --output DIR Specify output directory
COMMANDS copy Copy files to output directory move Move files to output directory list List file information
EXAMPLES $0 copy file1.txt file2.txt $0 -v --output /tmp move *.log $0 list document.pdf
EXIT STATUS 0 Success 1 General error 2 Invalid arguments
EOF
}
`
Examples and Use Cases
Example 1: File Backup Script
`bash
#!/bin/bash
backup.sh - Create backups of specified files
backup_dir="/backup" timestamp=$(date +%Y%m%d_%H%M%S) verbose=false
Process options
while getopts "d:vh" opt; do case $opt in d) backup_dir="$OPTARG" ;; v) verbose=true ;; h) echo "Usage: $0 [-d backup_dir] [-v] file1 [file2...]" exit 0 ;; esac done shift $((OPTIND-1))Check arguments
if [ $# -eq 0 ]; then echo "Error: No files specified" >&2 exit 1 fiCreate backup directory
mkdir -p "$backup_dir" || { echo "Error: Cannot create backup directory" >&2 exit 1 }Backup files
for file in "$@"; do if [ -f "$file" ]; then backup_name="${backup_dir}/$(basename "$file").${timestamp}" cp "$file" "$backup_name" if [ "$verbose" = true ]; then echo "Backed up: $file -> $backup_name" fi else echo "Warning: $file not found" >&2 fi doneecho "Backup completed. Files saved to $backup_dir"
`
Example 2: Log Analyzer Script
`bash
#!/bin/bash
log_analyzer.sh - Analyze log files
declare -A options=( [lines]=10 [pattern]="" [output]="" [case_sensitive]=true )
Process arguments
while [[ $# -gt 0 ]]; do case $1 in -n|--lines) options[lines]="$2" shift 2 ;; -p|--pattern) options[pattern]="$2" shift 2 ;; -o|--output) options[output]="$2" shift 2 ;; -i|--ignore-case) options[case_sensitive]=false shift ;; -*) echo "Unknown option: $1" >&2 exit 1 ;; *) log_files+=("$1") shift ;; esac doneValidate log files
if [ ${#log_files[@]} -eq 0 ]; then echo "Error: No log files specified" >&2 exit 1 fiProcess each log file
for log_file in "${log_files[@]}"; do if [ ! -f "$log_file" ]; then echo "Warning: $log_file not found" >&2 continue fi echo "Analyzing: $log_file" # Build grep command grep_cmd="grep" if [ "${options[case_sensitive]}" = false ]; then grep_cmd="$grep_cmd -i" fi if [ -n "${options[pattern]}" ]; then if [ -n "${options[output]}" ]; then $grep_cmd "${options[pattern]}" "$log_file" | tail -n "${options[lines]}" >> "${options[output]}" else $grep_cmd "${options[pattern]}" "$log_file" | tail -n "${options[lines]}" fi else if [ -n "${options[output]}" ]; then tail -n "${options[lines]}" "$log_file" >> "${options[output]}" else tail -n "${options[lines]}" "$log_file" fi fi done`Example 3: System Information Script
`bash
#!/bin/bash
sysinfo.sh - Display system information
show_usage() { cat << EOF Usage: $0 [OPTIONS]
Options: -a, --all Show all information -c, --cpu Show CPU information -m, --memory Show memory information -d, --disk Show disk information -n, --network Show network information -s, --services Show running services -h, --help Show this help
Examples: $0 -a # Show all information $0 -c -m # Show CPU and memory info $0 --disk --network # Show disk and network info EOF }
show_cpu() { echo "=== CPU Information ===" lscpu | grep -E "Model name|CPU\(s\)|Thread|Core" echo }
show_memory() { echo "=== Memory Information ===" free -h echo }
show_disk() { echo "=== Disk Information ===" df -h echo }
show_network() { echo "=== Network Information ===" ip addr show | grep -E "inet |link" echo }
show_services() { echo "=== Running Services ===" systemctl list-units --type=service --state=running | head -20 echo }
Default options
show_all=false show_cpu_info=false show_mem_info=false show_disk_info=false show_net_info=false show_svc_info=falseParse arguments
while [[ $# -gt 0 ]]; do case $1 in -a|--all) show_all=true shift ;; -c|--cpu) show_cpu_info=true shift ;; -m|--memory) show_mem_info=true shift ;; -d|--disk) show_disk_info=true shift ;; -n|--network) show_net_info=true shift ;; -s|--services) show_svc_info=true shift ;; -h|--help) show_usage exit 0 ;; *) echo "Unknown option: $1" >&2 show_usage exit 1 ;; esac doneShow information based on options
if [ "$show_all" = true ]; then show_cpu show_memory show_disk show_network show_services else # Show specific information [ "$show_cpu_info" = true ] && show_cpu [ "$show_mem_info" = true ] && show_memory [ "$show_disk_info" = true ] && show_disk [ "$show_net_info" = true ] && show_network [ "$show_svc_info" = true ] && show_services # If no specific options, show usage if [ "$show_cpu_info" = false ] && [ "$show_mem_info" = false ] && \ [ "$show_disk_info" = false ] && [ "$show_net_info" = false ] && \ [ "$show_svc_info" = false ]; then echo "No options specified. Use -h for help." exit 1 fi fi`Common Argument Patterns
Pattern Matching Table
| Pattern | Description | Example |
|---------|-------------|---------|
| $1 in .txt | Match file extension | if [[ "$1" == .txt ]]; then |
| [[ $# -eq n ]] | Exact argument count | if [[ $# -eq 2 ]]; then |
| [[ $# -lt n ]] | Minimum arguments | if [[ $# -lt 1 ]]; then |
| [[ -n "$1" ]] | Non-empty argument | if [[ -n "$1" ]]; then |
| [[ -z "$1" ]] | Empty argument | if [[ -z "$1" ]]; then |
Debugging Argument Processing
Debug Script Template
`bash
#!/bin/bash
Enable debug mode
set -x # Print commands as they execute set -e # Exit on any errordebug_args() { echo "=== Argument Debug Information ===" echo "Script name: $0" echo "Number of arguments: $#" echo "All arguments (\$@): $@" echo "All arguments (\$): $" echo "Process ID: $" local i=1 for arg in "$@"; do echo "Argument $i: [$arg]" ((i++)) done echo "==========================" }
Call debug function
debug_args "$@"Your script logic here
`This comprehensive guide covers all aspects of passing arguments to shell scripts, from basic positional parameters to advanced option processing. The examples demonstrate real-world usage patterns and best practices for creating robust, user-friendly shell scripts that can handle various input scenarios effectively.