Skip to content

Instantly share code, notes, and snippets.

@timokoola
Created March 26, 2025 06:59
Show Gist options
  • Select an option

  • Save timokoola/2a7c3006df05bc9718b78326f6237b50 to your computer and use it in GitHub Desktop.

Select an option

Save timokoola/2a7c3006df05bc9718b78326f6237b50 to your computer and use it in GitHub Desktop.

Revisions

  1. timokoola created this gist Mar 26, 2025.
    184 changes: 184 additions & 0 deletions list_profiles.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,184 @@
    #!/bin/bash
    #
    # Chrome Profile Lister
    # Lists all Google Chrome profiles with email addresses only
    # Format designed for easy selection and extraction in Keyboard Maestro
    #

    # Process command-line options
    SHOW_HEADER=true
    FORMAT="default"

    while [[ $# -gt 0 ]]; do
    case $1 in
    --no-header)
    SHOW_HEADER=false
    shift
    ;;
    --format)
    FORMAT="$2"
    shift 2
    ;;
    *)
    echo "Unknown option: $1"
    echo "Usage: $0 [--no-header] [--format km|default]"
    exit 1
    ;;
    esac
    done

    # Set the Chrome profile directory path
    CHROME_DIR="$HOME/Library/Application Support/Google/Chrome"

    # Check if Chrome directory exists
    if [ ! -d "$CHROME_DIR" ]; then
    echo "Chrome directory not found: $CHROME_DIR"
    exit 1
    fi

    # Function to extract email from a preferences file
    extract_email() {
    local pref_file="$1"

    # Check if the file exists
    if [ ! -f "$pref_file" ]; then
    echo ""
    return
    fi

    # Extract email using grep and sed
    # Look for email in the preferences file
    local email=$(grep -o '"email":"[^"]*"' "$pref_file" | head -1 | sed 's/"email":"//;s/"$//')

    # If email not found, check for account info
    if [ -z "$email" ]; then
    email=$(grep -o '"last_used_user_account":"[^"]*"' "$pref_file" | head -1 | sed 's/"last_used_user_account":"//;s/"$//')
    fi

    echo "$email"
    }

    # Function to extract profile name
    extract_profile_name() {
    local pref_file="$1"
    local profile_dir="$2"

    # Default name based on directory
    local default_name=$(basename "$profile_dir")

    # Check if the file exists
    if [ ! -f "$pref_file" ]; then
    echo "$default_name"
    return
    fi

    # Extract profile name using grep and sed
    local name=$(grep -o '"name":"[^"]*"' "$pref_file" | head -1 | sed 's/"name":"//;s/"$//')

    # If no name found, use directory name
    if [ -z "$name" ]; then
    echo "$default_name"
    else
    echo "$name"
    fi
    }

    # Function to extract domain from email
    extract_domain() {
    local email="$1"
    if [[ "$email" == *"@"* ]]; then
    echo "${email#*@}"
    else
    echo "zzznotsignedin"
    fi
    }

    # Function to extract local part from email
    extract_local_part() {
    local email="$1"
    if [[ "$email" == *"@"* ]]; then
    echo "${email%%@*}"
    else
    echo "$email"
    fi
    }

    # Temporary file for profile data
    TEMP_FILE=$(mktemp)

    # Function to collect profile information
    collect_profile_info() {
    local profile_dir="$1"
    local profile_name=$(extract_profile_name "$profile_dir/Preferences" "$profile_dir")
    local email=$(extract_email "$profile_dir/Preferences")

    # Skip if no email (not signed in)
    if [ -z "$email" ]; then
    return
    fi

    if [ "$FORMAT" = "km" ]; then
    # Store domain, local part, and profile info for sorting
    domain=$(extract_domain "$email")
    local_part=$(extract_local_part "$email")

    # Store full profile information for KM format
    # Format: "Display Name|email_address"
    echo "$domain|$local_part|$profile_name ($domain)|$email" >> "$TEMP_FILE"
    else
    # Default format - just print
    printf "%-20s %-35s %s\n" "$profile_name" "$email" "$profile_dir"
    fi
    }

    # Print header if requested for default format
    if [ "$SHOW_HEADER" = true ] && [ "$FORMAT" = "default" ]; then
    echo "===== Chrome Profiles with Email ====="
    printf "%-20s %-35s %s\n" "Profile Name" "Email Address" "Profile Directory"
    echo "------------------------------------------------------------------------------------"
    fi

    # Process Default profile
    if [ -d "$CHROME_DIR/Default" ]; then
    if [ "$FORMAT" = "default" ]; then
    profile_name=$(extract_profile_name "$CHROME_DIR/Default/Preferences" "$CHROME_DIR/Default")
    email=$(extract_email "$CHROME_DIR/Default/Preferences")
    if [ -n "$email" ]; then
    printf "%-20s %-35s %s\n" "$profile_name" "$email" "$CHROME_DIR/Default"
    fi
    else
    collect_profile_info "$CHROME_DIR/Default"
    fi
    fi

    # Process numbered profiles
    find "$CHROME_DIR" -maxdepth 1 -type d -name "Profile*" | sort | while read -r profile_dir; do
    # Skip if directory doesn't exist
    if [ ! -d "$profile_dir" ]; then
    continue
    fi

    if [ "$FORMAT" = "default" ]; then
    profile_name=$(extract_profile_name "$profile_dir/Preferences" "$profile_dir")
    email=$(extract_email "$profile_dir/Preferences")
    if [ -n "$email" ]; then
    printf "%-20s %-35s %s\n" "$profile_name" "$email" "$profile_dir"
    fi
    else
    collect_profile_info "$profile_dir"
    fi
    done

    # For KM format, output the sorted list with display names and emails separated by |
    if [ "$FORMAT" = "km" ]; then
    # Sort the data by domain and then by local part
    sort "$TEMP_FILE" -o "$TEMP_FILE"

    # Output the sorted data in a format Keyboard Maestro can easily parse
    while IFS="|" read -r domain local_part display_name email; do
    echo "$display_name|$email"
    done < "$TEMP_FILE"
    fi

    # Clean up
    rm -f "$TEMP_FILE"
    129 changes: 129 additions & 0 deletions open_profile.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,129 @@
    #!/bin/bash
    #
    # Chrome Profile Opener
    # Opens a new Chrome window with the specified profile (by email address or directory name)
    #

    # Process command line options
    USE_DIRECTORY=false
    EMAIL=""
    DIRECTORY=""

    # Parse arguments
    while [[ $# -gt 0 ]]; do
    case $1 in
    --directory)
    USE_DIRECTORY=true
    DIRECTORY="$2"
    shift 2
    ;;
    *)
    EMAIL="$1"
    shift
    ;;
    esac
    done

    # Check if either email or directory was provided
    if [ "$USE_DIRECTORY" = false ] && [ -z "$EMAIL" ]; then
    echo "Usage: $0 <email_address> OR $0 --directory <directory_name>"
    exit 1
    fi

    if [ "$USE_DIRECTORY" = true ] && [ -z "$DIRECTORY" ]; then
    echo "Error: No directory specified with --directory flag"
    exit 1
    fi

    CHROME_DIR="$HOME/Library/Application Support/Google/Chrome"
    CHROME_APP="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"

    # Alternative Chrome locations to check if the default isn't found
    ALT_CHROME_LOCATIONS=(
    "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
    "/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta"
    "/Applications/Google Chrome Dev.app/Contents/MacOS/Google Chrome Dev"
    "/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary"
    )

    # Find Chrome executable
    for chrome_path in "${ALT_CHROME_LOCATIONS[@]}"; do
    if [ -f "$chrome_path" ]; then
    CHROME_APP="$chrome_path"
    break
    fi
    done

    # Check if Chrome executable exists
    if [ ! -f "$CHROME_APP" ]; then
    echo "Error: Google Chrome application not found"
    exit 1
    fi

    # Function to find profile directory by email
    find_profile_by_email() {
    local email="$1"
    local profile_dir=""

    # Check Default profile first
    if [ -f "$CHROME_DIR/Default/Preferences" ]; then
    local default_email=$(grep -o '"email":"[^"]*"' "$CHROME_DIR/Default/Preferences" | head -1 | sed 's/"email":"//;s/"$//')
    if [ -z "$default_email" ]; then
    default_email=$(grep -o '"last_used_user_account":"[^"]*"' "$CHROME_DIR/Default/Preferences" | head -1 | sed 's/"last_used_user_account":"//;s/"$//')
    fi
    if [ "$default_email" = "$email" ]; then
    echo "Default"
    return 0
    fi
    fi

    # Check numbered profiles
    find "$CHROME_DIR" -maxdepth 1 -type d -name "Profile*" | while read -r dir; do
    if [ -f "$dir/Preferences" ]; then
    local profile_email=$(grep -o '"email":"[^"]*"' "$dir/Preferences" | head -1 | sed 's/"email":"//;s/"$//')
    if [ -z "$profile_email" ]; then
    profile_email=$(grep -o '"last_used_user_account":"[^"]*"' "$dir/Preferences" | head -1 | sed 's/"last_used_user_account":"//;s/"$//')
    fi

    if [ "$profile_email" = "$email" ]; then
    # Extract profile name from directory path
    echo "$(basename "$dir")"
    return 0
    fi
    fi
    done

    # If no matching profile found
    echo ""
    return 1
    }

    # Main execution path
    if [ "$USE_DIRECTORY" = true ]; then
    # Using directory directly
    if [ "$DIRECTORY" = "Default" ]; then
    PROFILE="Default"
    else
    PROFILE="$DIRECTORY"
    fi

    echo "Opening Chrome with profile directory: $PROFILE"
    else
    # Using email to find profile
    PROFILE=$(find_profile_by_email "$EMAIL")

    if [ -z "$PROFILE" ]; then
    echo "Error: No Chrome profile found for email: $EMAIL"
    exit 1
    fi

    echo "Opening Chrome with profile: $PROFILE ($EMAIL)"
    fi

    # Open Chrome with the specified profile
    "$CHROME_APP" --profile-directory="$PROFILE" --new-window &

    # Wait a moment to ensure Chrome launches before script exits
    sleep 1

    exit 0