Study guide
7.3 Process Script Inputs ($1, $2, and Beyond)
Red Hat Certified System Administrator RHCSA
Track your progress as you read
Finished sections get a check mark.
1 Introduction & Exam Overview
1.1 Current Exam Facts 1.2 Lab Setup & Performance-Based Study Strategy
2 Essential Tools: Shell, Redirection & Text Analysis
2.1 Shell Prompt and Command Syntax 2.2 Input-Output Redirection and Pipes 2.3 grep and Regular Expressions for Text Analysis
3 Essential Tools: Remote Access, Users & Text Editing
3.1 Access Remote Systems Using SSH 3.2 Log In and Switch Users in Multiuser Targets 3.3 Create and Edit Text Files
4 Essential Tools: Files, Links & Archives
4.1 Create, Delete, Copy, and Move Files and Directories 4.2 Hard and Soft Links 4.3 Archive and Compress with tar, gzip, and bzip2
5 Essential Tools: Permissions & System Documentation
5.1 List, Set, and Change Standard ugo/rwx Permissions 5.2 System Documentation: man, info, and /usr/share/doc
6 Manage Software: RPM and Flatpak
6.1 Configure Access to RPM Repositories 6.2 Install and Remove RPM Software Packages 6.3 Configure Access to Flatpak Repositories 6.4 Install and Remove Flatpak Software Packages
7 Create Simple Shell Scripts
7.1 Conditional Execution: if, test, and [] 7.2 Looping Constructs for Files and Input 7.3 Process Script Inputs ($1, $2, and Beyond) 7.4 Process Shell Command Output in Scripts
8 Operate Running Systems: Boot and Recovery
8.1 Boot, Reboot, and Shut Down a System Normally 8.2 Boot Systems into Different Targets Manually 8.3 Interrupt the Boot Process to Gain Access
9 Operate Running Systems: Processes and Tuning
9.1 Identify and Kill CPU/Memory Intensive Processes 9.2 Adjust Process Scheduling 9.3 Manage Tuning Profiles
10 Operate Running Systems: Logs, Services & File Transfer
10.1 Locate and Interpret System Log Files and Journals 10.2 Preserve System Journals 10.3 Start, Stop, and Check Status of Network Services 10.4 Securely Transfer Files Between Systems
11 Configure Local Storage: Partitions and LVM
11.1 List, Create, and Delete Partitions on GPT Disks 11.2 Create and Remove Physical Volumes 11.3 Assign Physical Volumes to Volume Groups 11.4 Create and Delete Logical Volumes
12 Configure Local Storage: Mounting and Expansion
12.1 Mount File Systems at Boot by UUID or Label 12.2 Add Partitions, Logical Volumes, and Swap Non-Destructively
13 Create and Configure File Systems: Local FS and Permissions
13.1 Create, Mount, and Use VFAT, ext4, and XFS File Systems 13.2 Extend Existing Logical Volumes 13.3 Diagnose and Correct File Permission Problems
14 Create and Configure File Systems: NFS and autofs
14.1 Mount and Unmount Network File Systems Using NFS 14.2 Configure autofs
15 Deploy and Maintain: Scheduling, Services & Targets
15.1 Schedule Tasks with at, cron, and systemd Timers 15.2 Start, Stop, and Enable Services at Boot 15.3 Configure Systems to Boot into a Specific Target
16 Deploy and Maintain: Time, Software Updates & Bootloader
16.1 Configure Time Service Clients 16.2 Install and Update Software from CDN, Remote Repos, and Local Files 16.3 Modify the System Bootloader
17 Manage Basic Networking
17.1 Configure IPv4 and IPv6 Addresses 17.2 Configure Hostname Resolution 17.3 Configure Network Services to Start Automatically at Boot 17.4 Restrict Network Access Using firewalld and firewall-cmd
18 Manage Users and Groups
18.1 Create, Delete, and Modify Local User Accounts 18.2 Change Passwords and Adjust Password Aging 18.3 Create, Delete, and Modify Local Groups and Memberships 18.4 Configure Privileged Access
19 Manage Security: Firewall, umask & SSH Keys
19.1 Configure Firewall Settings with firewall-cmd and firewalld 19.2 Manage Default File Permissions 19.3 Configure Key-Based Authentication for SSH
20 Manage Security: SELinux Modes and Contexts
20.1 Set Enforcing and Permissive Modes for SELinux 20.2 List and Identify SELinux File and Process Contexts 20.3 Restore Default File Contexts
21 Manage Security: SELinux Ports and Booleans
21.1 Manage SELinux Port Labels 21.2 Use Boolean Settings to Modify SELinux Settings
7.3 Process Script Inputs ($1, $2, and Beyond)
Key Takeaways Explain This Topic AI
Positional parameters $1, $2, $3… hold command-line arguments; $0 is the script name as invoked.
$# is the argument count; "$@" is all arguments as separate words; "$*" joins arguments into one word (IFS first character)—prefer "$@" for safe iteration.
Validate inputs with [ $# -eq N ], -z tests, and usage messages on stderr before changing the system.
shift discards $1 and renumbers remaining parameters—useful for option parsing in simple scripts.
Exam scripts must behave correctly for missing, extra, or wrong-type arguments: check, message, non-zero exit.
Last updated: August 2026
7.3 Process Script Inputs ($1, $2, and Beyond)
Quick Answer: Arguments appear as $1 , $2 , …; $0 is the script name; $# is how many arguments were passed; iterate safely with for arg in "$@"; do ...; done . Check counts and values with if / [ ] before acting. Prefer "$@" over unquoted $* .
Why inputs matter on the exam
A script that only hard-codes /tmp/foo is easy to write and often wrong for the task . Graders pass arguments or expect the script to read parameters the task describes:
- ./mkuser.sh jdoe
- ./backup.sh /data /mnt/backup
- ./check.sh file1 file2 file3
You must process those inputs, not ignore them.
Positional parameters map
- Parameter Meaning
- $0 Script name as invoked ( ./tool.sh or full path)
- $1 First argument
- $2 Second argument
- $3 … $9 Third through ninth
- ${10} , ${11} , … Tenth and beyond— use braces
- $# Number of arguments (not counting $0 )
- $* All arguments (joining rules below)
- $@ All arguments (joining rules below)
- $$ PID of the shell (not an input; useful in temp names)
- $? Exit status of last command (not an input) #!/bin/bash
- echo "script=$0"
- echo "count=$#"
- echo "first=$1"
- echo "second=$2"
- Run: chmod +x demo.sh
- ./demo.sh alpha beta
- # script=./demo.sh
- # count=2
- # first=alpha
- # second=beta
- Braces for clarity and double digits echo "${1}"
- echo "${10}" # not $10 which is $1 followed by 0
- " @ " v s " @" vs " @" v s " *" vs unquoted forms
This distinction is a classic gotcha.
- Form Behavior (typical)
- "$@" Each argument is a separate word, even with spaces
- "$*" All arguments joined into one word using the first IFS character (usually space)
- $@ / $* unquoted Subject to word-splitting and globbing— unsafe #!/bin/bash
- # Safe: preserves "My File.txt" as one argument
- for f in "$@"; do
- echo "arg=[$f]"
done # Dangerous if an argument has spaces:
- for f in $*; do
- echo "split badly: $f"
- done
Exam rule of thumb: loop with for x in "$@"; do and expand individuals as "$1" , "$2" .
- Validating argument count #!/bin/bash
- if [ $# -ne 2 ]; then
- echo "Usage: $0 source_dir dest_dir" >&2
- exit 2
- fi
- SRC="$1"
- DST="$2"
Common checks:
- Test Meaning
- [ $# -eq 0 ] No arguments
- [ $# -ne 1 ] Not exactly one
- [ $# -lt 2 ] Fewer than two
- [ $# -gt 5 ] Too many
Exit code 2 is a conventional “usage error”; 1 is general failure. Be consistent within a script.
- Validating argument meaning
- Count alone is not enough: #!/bin/bash
- if [ $# -ne 1 ]; then
- echo "Usage: $0 existing-directory" >&2
- exit 2
- fi
- if [ ! -d "$1" ]; then
- echo "Not a directory: $1" >&2
- exit 1
- fi
- if [ ! -w "$1" ]; then
- echo "Directory not writable: $1" >&2
- exit 1
- fi
- echo "OK to use $1"
- Other frequent validations: # Non-empty string
- [ -z "$1" ] && { echo "empty" >&2; exit 2; }
- # User exists
- id "$1" &>/dev/null || { echo "no such user" >&2; exit 1; }
- # Absolute path required by task
- case "$1" in
- /*) ;;
- *) echo "need absolute path" >&2; exit 2 ;;
- esac
case is optional sugar; nested if is fine on EX200.
- Assigning to named variables
- Immediately copy positionals into readable names after validation: USER_NAME="$1"
- COMMENT="$2"
- HOME_BASE="${3:-/home}" # default if $3 unset/null
${VAR:-default} supplies a default—handy when an argument is optional.
- Expansion Meaning
- ${1:-default} Use default if $1 unset or null
- ${1:=default} Assign default to $1 if unset/null (positional assignment is special—prefer named vars)
- ${1:?message} Exit if unset/null, print message
- ${#1} Length of $1 string
Prefer named variables after the first few lines so later logic does not confuse $1 after shift .
- shift — walk arguments
- shift removes $1 and renumbers: old $2 becomes $1 , and $# decreases by one. #!/bin/bash
- # sum.sh — add numeric arguments
- if [ $# -eq 0 ]; then
- echo "Usage: $0 numbers..." >&2
- exit 2
- fi
- sum=0
- while [ $# -gt 0 ]; do
- sum=$((sum + $1))
- shift
- done
- echo "$sum"
- Option-style parsing (simple): #!/bin/bash
- VERBOSE=0
- while [ $# -gt 0 ]; do
- case "$1" in
- v) VERBOSE=1; shift ;;
- h|--help) echo "Usage: $0 [-v] file"; exit 0 ;;
- -) shift; break ;;
- *) echo "Unknown option: $1" >&2; exit 2 ;;
- *) break ;;
- esac
- done
- # remaining "$@" are files
- for f in "$@"; do
...
done
Full getopts is optional knowledge; simple case + shift covers many exam scripts.
- Interactive input: read (when the task asks)
- Most EX200 scripts take CLI args , not prompts. If a task says “ask the user,” use read : #!/bin/bash
- read -r -p "Username: " USER_NAME
- if [ -z "$USER_NAME" ]; then
- echo "empty name" >&2
- exit 2
- fi
Do not mix interactive read into scripts the grader runs non-interactively unless the task requires it—your script would hang.
- Environment variables as inputs
- Sometimes configuration comes from the environment: #!/bin/bash
- MODE="${MODE:-enforce}"
- if [ "$MODE" != "enforce" ] && [ "$MODE" != "permissive" ]; then
- echo "MODE must be enforce or permissive" >&2
- exit 2
- fi
Run as MODE=permissive ./script.sh . Prefer explicit $1 when the task lists command-line parameters.
End-to-end exam script
Task: Create /usr/local/bin/hostcheck.sh that takes one hostname argument, pings once, prints OK or FAIL, exits 0/1, and rejects wrong usage. #!/bin/bash
- if [ $# -ne 1 ]; then
- echo "Usage: $0 hostname" >&2
- exit 2
- fi
- HOST="$1"
- if ping -c1 -W2 "$HOST" &>/dev/null; then
- echo "OK $HOST"
- exit 0
- else
- echo "FAIL $HOST"
- exit 1
- fi sudo tee /usr/local/bin/hostcheck.sh >/dev/null <<'EOF'
...paste script...
- EOF
- sudo chmod +x /usr/local/bin/hostcheck.sh
- hostcheck.sh server1.example.com
echo $?
- Task: Script accepts multiple files; print line counts; skip missing files with a message. #!/bin/bash
- if [ $# -eq 0 ]; then
- echo "Usage: $0 file..." >&2
- exit 2
- fi
- for f in "$@"; do
- if [ -f "$f" ]; then
- lines=$(wc -l < "$f")
- echo "$f $lines"
- else
- echo "missing: $f" >&2
- fi
- done
- Special: $0 in usage messages
- Always print usage with "$0" so users see the real invocation name: echo "Usage: $0 USER DIR" >&2
Hard-coding ./script.sh confuses when the script is installed in /usr/local/bin .
Debugging inputs bash -x ./script.sh arg1 arg2
# or inside script temporarily:
printf 'DEBUG: count=%s a1=%q a2=%q\n' "$#" "$1" "$2" >&2
%q shell-escapes values for visibility of spaces/newlines.
Common traps
Using $1 after shift without re-checking — it is a different value now.
$# vs ${#1} — count of args vs length of first arg string.
Unquoted $@ — breaks on spaces.
Forgetting ${10} braces — $10 ≠ tenth argument.
No usage message / always exit 0 — grader cannot distinguish success from silent misuse.
Reading $1 but documenting two required args — validate $# honestly.
Assuming interactive read when automation supplies args only.
Relationship to other sections
Inputs feed conditionals (empty? exists?) and loops ( for arg in "$@" ). The next section shows how to capture command output into variables that may also become inputs to later decisions.
Section checkpoint
You should read $1 / $2 /…, report $# , iterate with "$@" , understand "$*" joining, shift through a list, validate counts and types, set defaults with ${var:-default} , print usage via $0 , and exit non-zero on bad input—core EX200 script input processing.