Skip to content

Setup — Menu-Driven CLI App

Create the project structure and understand the tools you'll use.

Directory Structure

mkdir -p ~/projects/taskman
cd ~/projects/taskman
touch taskman.sh taskman.conf
chmod +x taskman.sh

Your project:

~/projects/taskman/ ├── taskman.sh ← main script ├── taskman.conf ← user preferences └── tasks.db ← task data (created on first run)

Understand select

select is bash's built-in for creating numbered menus:

#!/usr/bin/env bash
options=("List files" "Show date" "Quit")
select choice in "${options[@]}"; do
    case "$choice" in
        "List files") ls ;;
        "Show date")  date ;;
        "Quit")       break ;;
        *) echo "Invalid option $REPLY" ;;
    esac
done

Run this snippet to see select in action:

bash -c '
options=("List files" "Show date" "Quit")
select choice in "${options[@]}"; do
    case "$choice" in
        "List files") ls; break ;;
        "Show date")  date; break ;;
        "Quit")       break ;;
    esac
done'
1) List files 2) Show date 3) Quit #? 2 Tue Jan 15 09:00:00 UTC 2024

Understand ANSI Color Codes

# Color escape codes
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
RESET='\033[0m'

echo -e "${GREEN}This is green${RESET}"
echo -e "${RED}This is red${RESET}"
echo -e "${BOLD}This is bold${RESET}"
This is green (appears green) This is red (appears red) This is bold (appears bold)

Colors in non-interactive terminals

Always check [[ -t 1 ]] (stdout is a terminal) before using colors. When output is piped to a file or another command, ANSI codes appear as garbage characters.

[[ -t 1 ]] && GREEN='\033[0;32m' || GREEN=''

Understand the Data Format

Practice parsing the task database format:

# Sample data
echo "1:done:high:Buy milk" | awk -F: '{print $1, $2, $3, $4}'
1 done high Buy milk
# Find pending tasks
echo -e "1:done:high:Buy milk\n2:pending:normal:Write readme" |
awk -F: '$2 == "pending" {print $1, $4}'
2 Write readme

Create a Sample Config File

cat > ~/projects/taskman/taskman.conf << 'EOF'
# taskman.conf — user preferences
DB_FILE="${HOME}/projects/taskman/tasks.db"
DEFAULT_PRIORITY=normal
SHOW_DONE=true
MAX_DISPLAY=50
EOF

requirements | implementation