Shell Scripting Interview Questions and Answers
Shell Scripting Basics
1. What is a shell, and what is the purpose of shell scripting?
A shell is a command-line interpreter that provides a user interface for accessing the services of the operating system. It takes commands from the user (e.g., ls, grep) and executes them.
Shell scripting is the practice of writing scripts containing a series of commands for the shell to execute. The purpose of shell scripting is to automate repetitive tasks, saving time and reducing the potential for human error. Common use cases include: * Automating system administration tasks (backups, user management). * Deploying applications. * Running a sequence of commands for a data processing pipeline. * Simplifying complex workflows into a single command.
2. Explain the significance of the "shebang" line (#!/bin/bash) at the beginning of a script.
The shebang (#!) is the very first line of a script. It specifies the absolute path to the interpreter that should be used to execute the rest of the file.
#!/bin/bash: Tells the system to use the Bash shell.#!/usr/bin/env python3: Tells the system to find thepython3interpreter in the user's environment path and use it.
Why it's important: It ensures that the script is executed by the correct interpreter, regardless of the user's default shell or how the script is invoked. This makes scripts portable and predictable.
3. How do you make a shell script executable?
You use the chmod (change mode) command to add execute permission (+x).
# Add execute permission for the current user
chmod u+x my_script.sh
# Add execute permission for the user, group, and others
chmod +x my_script.sh
After making it executable, you can run it directly from the terminal:
./my_script.sh
Variables and Arguments
4. What are the different types of variables in shell scripting?
- User-defined Variables: Variables created by the user. By convention, these are often lowercase.
bash my_variable="Hello, World!" echo $my_variable - System Variables (Environment Variables): Predefined variables set by the system that control the shell's behavior. They are always in uppercase.
HOME: The path to the current user's home directory.PATH: A colon-separated list of directories the shell searches for commands.USER: The username of the current user.PWD: The current working directory.
5. How do you handle command-line arguments? Explain `,$#,$@, and$?`.
Command-line arguments are passed to a script after its name (e.g., ./my_script.sh arg1 arg2). They are accessed using special positional parameters.
`,$2, ...$n`: Represent the first, second, and nth argument.$0: The name of the script itself.$#: The total number of arguments passed to the script.$@: Represents all arguments as a list of separate, quoted strings ("" "$2" ...). This is the safest and most common way to pass all arguments to another command.$*: Represents all arguments as a single string (" $2 ...").$?: The exit status of the last executed command.0means success, and any non-zero value means failure.$: The Process ID (PID) of the current shell.
Example Script (user_info.sh):
#!/bin/bash
# Check if the correct number of arguments is provided
if [ "$#" -ne 2 ]; then
echo "Usage: $0 <username> <action>"
exit 1
fi
echo "Executing script: $0"
echo "Username: "
echo "Action: $2"
echo "Total arguments: $#"
Execution:
./user_info.sh jdoe create
# Output:
# Executing script: ./user_info.sh
# Username: jdoe
# Action: create
# Total arguments: 2
Control Structures
6. How do you use conditional logic? Explain if and case statements.
Conditional logic allows a script to make decisions.
if, elif, else Statements:
Used for branching logic based on conditions. The conditions are evaluated using the test command ([ or [[ ]]).
- File/Directory Checks:
-f(file exists),-d(directory exists),-e(exists). - String Comparisons:
==or=(equal),!=(not equal),-z(is null). - Numeric Comparisons:
-eq(equal),-ne(not equal),-gt(greater than),-lt(less than).
Example:
#!/bin/bash
FILE_PATH="/etc/hosts"
COUNT=10
if [ -f "$FILE_PATH" ]; then
echo "File '$FILE_PATH' exists."
else
echo "File '$FILE_PATH' not found."
fi
if [ "$COUNT" -gt 5 ]; then
echo "Count is greater than 5."
fi
case Statement:
Used to simplify complex if/elif/else chains when matching a variable against several patterns.
Example:
#!/bin/bash
read -p "Enter 'start', 'stop', or 'restart': " ACTION
case $ACTION in
start)
echo "Starting the service..."
;;
stop)
echo "Stopping the service..."
;;
restart)
echo "Restarting the service..."
;;
*)
echo "Invalid action. Please enter 'start', 'stop', or 'restart'."
;;
esac
7. How do you use loops? Provide examples for for and while loops.
Loops are used to execute a block of code multiple times.
for Loop:
Iterates over a list of items.
- Iterating over a list of strings:
bash for server in "server1" "server2" "server3"; do echo "Pinging ${server}..." ping -c 1 $server done - Iterating over files in a directory:
bash for file in /var/log/*.log; do echo "Processing log file: $file" done
while Loop:
Executes a block of code as long as a condition is true. It is often used to read a file line by line.
- Simple counter:
bash i=1 while [ $i -le 5 ]; do echo "Count: $i" i=$((i+1)) done - Reading a file line by line (the standard, safe way):
bash FILENAME="/etc/passwd" while IFS= read -r line; do echo "Line: $line" done < "$FILENAME"IFS=: Prevents trimming of leading/trailing whitespace.-r: Prevents backslash interpretation.< "$FILENAME": Redirects the file's content into the loop.
Functions
8. How do you define and use functions in shell scripts?
Functions allow you to group a set of commands into a reusable block, making scripts more modular and readable.
Defining a Function:
function_name() {
# Commands go here
echo "This is a function."
# You can access arguments passed to the function using , $2, etc.
echo "First argument to function: "
}
Calling a Function: You simply use the function's name, followed by any arguments.
Example Script:
#!/bin/bash
# Define a function to print a log message with a timestamp
log() {
# is the first argument passed to the log function
local MESSAGE=""
echo "$(date '+%Y-%m-%d %H:%M:%S') - ${MESSAGE}"
}
# Call the function
log "Starting the backup process."
# ... backup commands ...
log "Backup process finished."
Execution Output:
2023-10-27 10:30:00 - Starting the backup process.
2023-10-27 10:30:05 - Backup process finished.
Practical Scripting Examples
9. What are best practices for error handling? Explain exit codes and set -e.
Proper error handling is crucial for writing robust scripts.
Exit Codes ($?)
Every command returns an exit code when it finishes. This is a number between 0 and 255.
* 0: The command was successful.
* 1-255: The command failed. Different numbers can signify different types of errors.
You can check the exit code of the most recently executed command using the special variable $?.
grep "search_term" /path/to/file
if [ "$?" -ne 0 ]; then
echo "Error: 'grep' command failed."
fi
set -e (Exit on Error)
Manually checking $? after every command is tedious. A better approach is to use set -e. This command, placed at the top of your script, will cause the script to exit immediately if any command fails (i.e., returns a non-zero exit code).
set -o pipefail
By default, a pipeline (command1 | command2) returns the exit code of the last command. If command1 fails but command2 succeeds, the pipeline is considered successful. set -o pipefail changes this behavior, causing the pipeline to fail if any command in it fails.
Best Practice Script Header:
#!/bin/bash
set -eo pipefail
# -e: Exit immediately if a command exits with a non-zero status.
# -o pipefail: The return value of a pipeline is the status of the last command
# to exit with a non-zero status, or zero if no command exited
# with a non-zero status.
echo "This will run."
false # This command fails, so the script will exit here.
echo "This will NOT run."
10. Write a script to find and replace a string in a file.
The sed (stream editor) command is perfect for this task.
#!/bin/bash
# A script to replace a string in a file.
# Usage: ./replace_string.sh <old_string> <new_string> <filename>
set -eo pipefail
if [ "$#" -ne 3 ]; then
echo "Usage: $0 <old_string> <new_string> <filename>"
exit 1
fi
OLD_STRING=
NEW_STRING=$2
FILENAME=$3
if [ ! -f "$FILENAME" ]; then
echo "Error: File '$FILENAME' not found."
exit 1
fi
echo "Replacing all occurrences of '${OLD_STRING}' with '${NEW_STRING}' in '$FILENAME'..."
# Use sed to find and replace the string.
# The 'g' flag means replace all occurrences on each line.
# The -i flag modifies the file in-place. For safety, you can create a backup: sed -i.bak 's/...'
sed -i "s/${OLD_STRING}/${NEW_STRING}/g" "$FILENAME"
echo "Replacement complete."
How to run it:
chmod +x replace_string.sh
./replace_string.sh "database_ip" "10.0.1.50" "config.yml"