2 - Advanced Bash Script
Linux Directory Structure
Section titled “Linux Directory Structure”
| Directories | Description |
|---|---|
| /bin | binary or executable programs. |
| /etc | system configuration files. |
| /home | home directory. It is the default current directory. |
| /opt | optional or third-party software. |
| /tmp | temporary space, typically cleared on reboot. |
| /usr | User related programs. |
| /var | log files. |
File descriptors
Section titled “File descriptors”File descriptors (FDs) are numeric identifiers that represent open files or streams in Unix/Linux systems. In bash, every process automatically gets three standard file descriptors:
Standard File Descriptors
0 - stdin (Standard Input)
-
Purpose: Where a program reads input from
-
Default: Connected to keyboard/terminal
-
Example: When you type commands or data
1 - stdout (Standard Output)
-
Purpose: Where a program sends normal output
-
Default: Connected to terminal screen
-
Example: Regular command output, echo results
2 - stderr (Standard Error)
-
Purpose: Where a program sends error messages
-
Default: Connected to terminal screen (same as stdout)
-
Example: Error messages, warnings
#!/bin/bash
echo "=== File Descriptor Redirection Demo ==="
# Setup: Create some test filesecho -e "banana\napple\ncherry" > fruits.txtecho "Setting up demo files..."
echo -e "\n1. REDIRECT STDOUT TO FILE"echo "This goes to a file" > message.txtecho "✓ Check message.txt - you won't see the output on screen"
echo -e "\n2. REDIRECT STDERR TO FILE"ls thisfiledoesnotexist 2> error_log.txtecho "✓ Error message went to error_log.txt instead of screen"
echo -e "\n3. REDIRECT BOTH STDOUT AND STDERR"# This command will produce both output and an error{ echo "Success message"; ls fakefile; } > all_output.txt 2>&1echo "✓ Both success and error messages went to all_output.txt"
echo -e "\n4. SHORTHAND FOR BOTH"{ echo "Another success"; ls anotherfakefile; } &> shorthand_output.txtecho "✓ Same result using &> shorthand"
echo -e "\n5. REDIRECT STDIN FROM FILE"echo "Sorting fruits from fruits.txt:"sort < fruits.txt
echo -e "\n6. DISCARD OUTPUT (send to /dev/null)"echo "Running ls on fake file - you won't see any error:"ls nonexistent 2> /dev/nullecho "✓ Error was discarded"
echo -e "\n7. DISCARD EVERYTHING"{ echo "This output disappears"; ls fakefile; } &> /dev/nullecho "✓ Both output and errors were discarded"
echo -e "\n=== Demo complete! Check these files: ==="echo "- message.txt"echo "- error_log.txt"echo "- all_output.txt"echo "- shorthand_output.txt"
# Cleanup optionecho -e "\nTo clean up demo files, run:"echo "rm -f message.txt error_log.txt all_output.txt shorthand_output.txt fruits.txt"local vs global variable
Section titled “local vs global variable”- Global variable
#!/bin/bash# Global variableusername="Alice"
function display_user() { echo "User: $username" # Can access global variable}
function change_user() { username="Bob" # Modifies the global variable!}
echo "Initial: $username" # Alicedisplay_user # User: Alicechange_userecho "After change: $username" # Bob (global was modified)OUTPUT
c@c:~/cos3105$ ./test.shInitial: AliceUser: AliceAfter change: Bob- local variable
#!/bin/bashusername="Alice" # Global
function test_local() { local username="Bob" # Local variable, shadows global echo "Inside function: $username" # Bob}
echo "Before: $username" # Alicetest_local # Inside function: Bobecho "After: $username" # Alice (global unchanged)OUTPUT
c@c:~/cos3105$ ./test.shBefore: AliceInside function: BobAfter: Aliceecho vs printf
Section titled “echo vs printf”- echo for simple output
- printf for formatted output
#!/bin/bashname="John"age=25score=87.5
# echo - basic concatenationecho "Name: $name, Age: $age, Score: $score"
# printf - formatted outputprintf "Name: %-10s Age: %3d Score: %6.2f\n" "$name" "$age" "$score"# Output: Name: John Age: 25 Score: 87.50
# Without formattingprintf "%s\n" "hello"# Output: hello
# With %-10s (left-aligned, 10 characters wide)printf "%-10s|\n" "hello"# Output: hello |# ^^^^^ ^ (5 spaces added to make it 10 chars total)
# Compare with right-aligned (no minus sign)printf "%10s|\n" "hello"# Output: hello|# ^^^^^ ^ (5 spaces before the text)OUTPUT
c@c:~/cos3105$ ./test.shName: John, Age: 25, Score: 87.5Name: John Age: 25 Score: 87.50hellohello | hello|Function with parameters and return value
Section titled “Function with parameters and return value”Example 1
Section titled “Example 1”#!/bin/bashvar1=$1var2=$2var3=$3var4=$4
add(){ #Note the $1 and $2 variables here are not the same of the #main script... echo "The first argument to this function is $1" echo "The second argument to this function is $2" result=$(($1+$2)) echo $result
}
add $var1 $var2add $var3 $var4OUTPUT
c@c:~/cos3105$ ./test.sh 1 2 3 4The first argument to this function is 1The second argument to this function is 23The first argument to this function is 3The second argument to this function is 47Example 2
Section titled “Example 2”#!/bin/bashvar1=$1var2=$2var3=$3var4=$4
add(){ result=$(($1+$2)) echo $result}minus(){ result=$(($1-$2)) echo $result}result1=$(add $var1 $var2)result2=$(add $var3 $var4)result3=$(minus $result2 $result1)echo "$result2 - $result1 = $result3"OUTPUT
c@c:~/cos3105$ ./test.sh 1 2 3 47 - 3 = 4Example 3
Section titled “Example 3”- read string into array
#!/bin/bash
read first second third <<< "a b c"echo $first # aecho $second # becho $third # c
# With -a (reads into array)read -a array <<< "a b c"echo ${array[0]} # aecho ${array[1]} # becho ${array[2]} # cOUTPUT
c@c:~/cos3105$ ./test.shabcabcExample 4
Section titled “Example 4”- return string of array and read array
#!/bin/bash
get_user_info() { echo "john" "doe" "30"}
read -a user_info <<< "$(get_user_info)"printf "Name = %s, Last name = %s, Age = %s\n" "${user_info[0]}" "${user_info[1]}" "${user_info[2]}"OUTPUT
c@c:~/cos3105$ ./test.shName = john, Last name = doe, Age = 30Example 5
Section titled “Example 5”- return string of array with comma separate and read array
IFS=", "for tells read to split string with", "
#!/bin/bash
get_user_info() { echo "john, doe, 30"}
IFS=", " read -a user_info <<< "$(get_user_info)"printf "Name = %s, Last name = %s, Age = %s\n" "${user_info[0]}" "${user_info[1]}" "${user_info[2]}"OUTPUT
c@c:~/cos3105$ ./test.shName = john, Last name = doe, Age = 30Terminal User Interface (TUI)
Section titled “Terminal User Interface (TUI)”- dialog: Original tool, developed first (1990s)
- whiptail: Fork/reimplementation of dialog, designed to be more lightweight
- dialog vs whiptail
- dialog more widgets and features
- whiptail less widgets
Example 1: Message Box
Section titled “Example 1: Message Box”message="Whiptail: Tool Basics"whiptail --msgbox --title "Intro to Whiptail" "$message" 0 0OUTPUT

Example 2: Yes/No dialog
Section titled “Example 2: Yes/No dialog”#!/bin/bash
if whiptail --title "Example Dialog" --yesno "This is an example of a yes/no box." 0 0; then echo "User selected Yes, exit status was $?."else echo "User selected No, exit status was $?."fi
Example 3: Input dialog
Section titled “Example 3: Input dialog”#!/bin/bashusername="$(whiptail --inputbox "What is your username?" 10 30 "$USER" 3>&1 1>&2 2>&3)"printf "Your username is : %s\n" "${username}"OUTPUT

Example 4: Password dialog
Section titled “Example 4: Password dialog”#!/bin/bashpassword="$(whiptail --passwordbox "Please enter your password:" 0 0 3>&1 1>&2 2>&3)"printf "Your password is : %s\n" "$password"OUTPUT

Example 5: Menu dialog
Section titled “Example 5: Menu dialog”#!/bin/bashresult=$(whiptail \ --menu "What is your favorite shell?" 0 0 2 \ "Bash" "(Bourne Again shell)" \ "Zsh" "(Z-Shell)" \ 3>&1 1>&2 2>&3)
echo "You selected: $result"OUTPUT

Example 6: Multiple selected dialog
Section titled “Example 6: Multiple selected dialog”#!/bin/bashresult=$(whiptail \ --checklist "What is your favorite shell?" 0 0 3 \ "Bash" "(Bourne Again shell)" 1 \ "Zsh" "(Z-Shell)" 0 \ "Dash" "(Dash shell)" 0 \ 3>&1 1>&2 2>&3)
echo "You selected: $result"OUTPUT

Example 7: Textbox with scroll text
Section titled “Example 7: Textbox with scroll text”#!/bin/bashcat > temp.txt << 'EOF'This is a very long text that will demonstratethe scrollable text box feature in whiptail.You can scroll up and down through this contentusing the arrow keys.
This is a very long text that will demonstratethe scrollable text box feature in whiptail.You can scroll up and down through this contentusing the arrow keys.
This is a very long text that will demonstratethe scrollable text box feature in whiptail.You can scroll up and down through this contentusing the arrow keys.EOF
whiptail --textbox temp.txt 0 0 --scrolltextrm temp.txtOUTPUT

Example 8: Radio lists
Section titled “Example 8: Radio lists”#!/bin/bashresult=$(whiptail \ --radiolist "What is your favorite shell?" 0 0 3 \ "Bash" "(Bourne Again shell)" 1 \ "Zsh" "(Z-Shell)" 0 \ "Dash" "(Dash shell)" 0 \ 3>&1 1>&2 2>&3)
echo "You selected: $result"OUTPUT

Example 9: Progress bar
Section titled “Example 9: Progress bar”#!/bin/bash
# Simple file processing progress bar{ for i in {0..100..20}; do echo "XXX" echo $i echo "Processing file $((i/20 + 1)) of 6..." echo "XXX" sleep 1 done} | whiptail --gauge "File Processing" 6 50 0
echo "Done!"OUTPUT

Handle errors from C program
Section titled “Handle errors from C program”- Example of C program
#include <stdio.h>#include <stdlib.h>
int main(int argc, char *argv[]) { if (argc < 2) { fprintf(stderr, "Usage: %s <command>\n", argv[0]); return 1; // Error code }
// Your logic here if (argc == 2) { fprintf(stderr, "Error: Something went wrong\n"); return 2; // Specific error code }
if (argc > 2) { fprintf(stderr, "Error: File not found\n"); return 3; // Different error code }
// Success case printf("Operation successful\n"); return 0; // Success}- Example of bash script
#!/bin/bash
# Capture stdout and stderr separatelyresult=$(./contacts2 mode email email_body 2>&1)exit_code=$?
if [ $exit_code -eq 0 ]; then echo "Success: $result"else echo "Error (exit code $exit_code): $result"fiOUTPUT
c@c:~/cos3105$ ./contacts2.shError (exit code 3): Error: File not found