Post

05. Control Structures in Shell Scripting

πŸš€ Master shell scripting control flow! Learn conditional statements, loops, case statements, and more to build powerful and efficient scripts. πŸ’‘

05. Control Structures in Shell Scripting

What we will learn in this post?

  • πŸ‘‰ Conditional Statements in Shell
  • πŸ‘‰ Looping in Shell
  • πŸ‘‰ Using Case Statements
  • πŸ‘‰ Break and Continue in Loops
  • πŸ‘‰ Combining Multiple Conditions in Shell
  • πŸ‘‰ Conclusion!

Conditional Statements in Python: if, if-else, elif

Conditional statements control the flow of your code based on whether a condition is true or false. Let’s explore them!

The if Statement πŸ‘¨β€πŸ’»

The simplest form checks a single condition.

1
2
3
import os
if os.path.exists("my_file.txt"):  #checks if file exists
    print("File exists!")

Example: Numerical Comparison

1
2
3
x = 10
if x > 5:
    print("x is greater than 5")

The if-else Statement βš–οΈ

This handles two possibilities: true or false.

1
2
3
4
5
age = 15
if age >= 18:
    print("You can vote!")
else:
    print("You are too young to vote.")

The elif Statement πŸ”€

Handles multiple conditions sequentially. It’s like saying, β€œif the first condition is false, then check this one, and then this one…”

1
2
3
4
5
6
7
8
9
score = 85
if score >= 90:
    print("A")
elif score >= 80:
    print("B")
elif score >= 70:
    print("C")
else:
    print("F")

More Info: For a deeper dive, check out the official Python documentation on conditional statements.

Note: Remember indentation is crucial in Python! Incorrect indentation will lead to errors. Use 4 spaces for consistent and readable code.

Shell Scripting Loops πŸŽ‰

Shell scripts use loops to repeat commands. Let’s explore for, while, and until loops!

Loop Types πŸ”„

  • for loop: Iterates over a list of items. Example: iterating through files in a directory:

    1
    
    for file in *.txt; do echo "$file"; done
    
  • while loop: Repeats as long as a condition is true. Example: prompting for user input until a specific value is entered:

    1
    
    while [[ "$input" != "quit" ]]; do read -p "Enter input (or 'quit'): " input; done
    
  • until loop: Repeats until a condition becomes true (opposite of while). Example: repeating a task until a file exists:

    1
    
    until [ -f "myfile.txt" ]; do echo "Waiting for myfile.txt..."; sleep 1; done
    

Numerical Ranges with for

You can also use for loops with numerical ranges using brace expansion or seq:

1
for i in {1..5}; do echo "$i"; done  #Prints 1 to 5

Applications πŸš€

Loops are useful for:

  • File processing: Processing multiple files, like converting images or extracting data.
  • User interaction: Creating interactive scripts that repeatedly ask for input.
  • Automation: Automating repetitive tasks, such as backups or system checks.

More Info: For a deeper dive, explore the Bash manual. Remember to always test your scripts carefully! πŸ˜‰

Shell Scripting’s case Statements: A Simpler Way

Understanding case Statements ✨

The case statement in shell scripts is like a super-charged if-else if-else structure. It elegantly handles multiple conditions based on a single variable’s value. Think of it as a powerful switch for your script’s logic!

Simple Example: A Menu

1
2
3
4
5
6
7
read -p "Enter choice (1-3): " choice
case $choice in
  1) echo "You chose option 1";;
  2) echo "You chose option 2";;
  3) echo "You chose option 3";;
  *) echo "Invalid choice";;
esac

This script presents a menu and uses case to execute different commands based on user input. *) acts as a default case for invalid input.

More Advanced Uses πŸš€

  • User Input Handling: Validate user input easily. Check for specific values or patterns.
  • Process Control: Decide what actions to take based on the outcome of other commands or events.

Example: Process Control

1
2
3
4
5
6
status=$?  #Check the exit status of a previous command
case $status in
  0) echo "Command succeeded!";;
  1) echo "Command failed!";;
  *) echo "Something unexpected happened!";;
esac

Flowchart:

graph TD
    A["⌨️ Read User Input"] --> B{"πŸ”€ Case Statement"};
    B -- πŸ…° Choice 1 --> C["βœ… Execute Option 1"];
    B -- πŸ…± Choice 2 --> D["βœ… Execute Option 2"];
    B -- πŸ…Ύ Choice 3 --> E["βœ… Execute Option 3"];
    B -- ❌ Default --> F["⚠️ Invalid Choice"];
    C --> G["🏁 End"];
    D --> G;
    E --> G;
    F --> G;

    %% Custom Styles
    classDef inputStyle fill:#FFD700,stroke:#B8860B,color:#000000,font-size:14px,stroke-width:3px,rx:15px,shadow:5px;
    classDef caseStyle fill:#1E90FF,stroke:#00008B,color:#FFFFFF,font-size:14px,stroke-width:3px,rx:15px,shadow:5px;
    classDef optionStyle fill:#32CD32,stroke:#006400,color:#FFFFFF,font-size:14px,stroke-width:3px,rx:15px,shadow:5px;
    classDef invalidStyle fill:#FF6347,stroke:#B22222,color:#FFFFFF,font-size:14px,stroke-width:3px,rx:15px,shadow:5px;
    classDef endStyle fill:#8A2BE2,stroke:#4B0082,color:#FFFFFF,font-size:14px,stroke-width:3px,rx:15px,shadow:5px;

    %% Apply Classes
    class A inputStyle;
    class B caseStyle;
    class C,D,E optionStyle;
    class F invalidStyle;
    class G endStyle;

For more information, explore these resources: Bash Guide, Advanced Bash Scripting Guide

Using case makes your shell scripts cleaner, more readable, and easier to maintain, especially when dealing with many conditional branches. It’s a fundamental tool for any shell scripting enthusiast! 😊

Controlling Loops with break and continue in Shell Scripting πŸŽ‰

Shell scripting offers break and continue statements to manage loop flow. These are invaluable for handling situations where you need to adjust loop behavior based on certain conditions.

The break Statement πŸ’₯

The break statement immediately terminates the loop it’s inside. Execution continues with the statement after the loop.

Example:

1
2
3
4
5
6
for i in {1..10}; do
  if [ $i -eq 5 ]; then
    break  # Exit loop when i equals 5
  fi
  echo $i
done

This loop will print numbers 1 through 4, then stop.

The continue Statement ⏩

continue skips the rest of the current iteration and proceeds to the next iteration of the loop.

Example:

1
2
3
4
5
6
for i in {1..10}; do
  if [ $((i % 2)) -eq 0 ]; then
    continue  # Skip even numbers
  fi
  echo $i
done

This loop prints only odd numbers (1, 3, 5, 7, 9).

Visualizing the Difference πŸ€”

graph TD
    A["πŸ” Start Loop"] --> B{"❓ Condition?"};
    B -- βœ… True --> C["⏹️ Break"];
    B -- ❌ False --> D["πŸ”„ Process Iteration"];
    D --> E["➑️ Next Iteration"];
    C --> F["🏁 End Loop"];
    E --> B;

    %% Custom Styles
    classDef loopStyle fill:#FFD700,stroke:#B8860B,color:#000000,font-size:14px,stroke-width:3px,rx:15px,shadow:5px;
    classDef conditionStyle fill:#1E90FF,stroke:#00008B,color:#FFFFFF,font-size:14px,stroke-width:3px,rx:15px,shadow:5px;
    classDef processStyle fill:#32CD32,stroke:#006400,color:#FFFFFF,font-size:14px,stroke-width:3px,rx:15px,shadow:5px;
    classDef breakStyle fill:#FF6347,stroke:#B22222,color:#FFFFFF,font-size:14px,stroke-width:3px,rx:15px,shadow:5px;
    classDef endStyle fill:#8A2BE2,stroke:#4B0082,color:#FFFFFF,font-size:14px,stroke-width:3px,rx:15px,shadow:5px;

    %% Apply Classes
    class A loopStyle;
    class B conditionStyle;
    class C breakStyle;
    class D,E processStyle;
    class F endStyle;

graph TD
    A["πŸ” Start Loop"] --> B{"❓ Condition?"};
    B -- βœ… True --> C["➑️ Continue"];
    B -- ❌ False --> D["πŸ”„ Process Iteration"];
    D --> E["➑️ Next Iteration"];
    C --> E;
    E --> B;

    %% Custom Styles
    classDef loopStyle fill:#FFD700,stroke:#B8860B,color:#000000,font-size:14px,stroke-width:3px,rx:15px,shadow:5px;
    classDef conditionStyle fill:#1E90FF,stroke:#00008B,color:#FFFFFF,font-size:14px,stroke-width:3px,rx:15px,shadow:5px;
    classDef processStyle fill:#32CD32,stroke:#006400,color:#FFFFFF,font-size:14px,stroke-width:3px,rx:15px,shadow:5px;
    classDef continueStyle fill:#FF8C00,stroke:#FF4500,color:#FFFFFF,font-size:14px,stroke-width:3px,rx:15px,shadow:5px;

    %% Apply Classes
    class A loopStyle;
    class B conditionStyle;
    class C continueStyle;
    class D,E processStyle;

(Note: These diagrams illustrate the flow; the exact implementation in shell scripting might vary slightly.)

Remember: These statements significantly improve the readability and efficiency of your shell scripts by allowing fine-grained control over looping. Use them wisely to create cleaner and more robust code!

Logical Operators in Shell Scripts 🀝

Shell scripts often need to check multiple conditions. This is where logical operators shine!

AND (&&) and OR (||)

  • && (AND): This operator executes the second command only if the first command succeeds (exits with a status code of 0). Think of it as β€œboth conditions must be true”.

  • || (OR): This operator executes the second command only if the first command fails (exits with a non-zero status code). Think of it as β€œat least one condition must be true”.

Examples

Let’s say you want to check if a file exists and is writable:

1
[ -f myfile.txt ] && [ -w myfile.txt ] && echo "File exists and is writable" || echo "File problem!"

This first checks if myfile.txt exists (-f), then if it’s writable (-w). Only if both are true, it prints the success message. Otherwise, the error message shows up.

Another example: Back up a file only if it’s modified since the last backup or it’s larger than 1GB:

1
[ $(stat -c %Y myfile.txt) -gt $(stat -c %Y backup.txt) ] || [ $(stat -c %s myfile.txt) -gt 1073741824 ] && cp myfile.txt backup.txt

This checks file modification time and size before creating a backup.

Remember: 0 means success, any other number means failure in shell return codes.

More info on Shell operators

Conclusion

And that’s a wrap! We hope you enjoyed this post. We’d love to hear your thoughts – what did you think? Any questions or suggestions? Let us know in the comments below! πŸ‘‡ Happy chatting! πŸ˜„

This post is licensed under CC BY 4.0 by the author.