#!/bin/bash # tmux-oneshot.sh # Run a single command in a tmux session # Built-in prompt patterns (command_pattern:prompt_pattern:timeout_seconds) PROMPT_PATTERNS=( "ssh*:Password|password:5" "sudo*:Password|password|\\[sudo\\] password for:5" "su*:Password|password:5" "mysql*:Enter password:3" "docker*:Password:2" ) # Generic function to wait for prompts based on command patterns wait_for_prompt() { local cmd="$1" # Find matching pattern for this command for pattern in "${PROMPT_PATTERNS[@]}"; do IFS=':' read -r cmd_pattern prompt_pattern timeout <<< "$pattern" if [[ "$cmd" == $cmd_pattern ]]; then echo "Waiting for prompt: $prompt_pattern (timeout: ${timeout}s)" timeout=$((timeout * 10)) # Convert to 0.1s intervals while [ $timeout -gt 0 ] && ! tmux capture-pane -t $SESSION -p | tail -3 | grep -E "($prompt_pattern)" >/dev/null 2>&1; do sleep 0.1 timeout=$((timeout - 1)) done if [ $timeout -eq 0 ]; then echo "Timeout waiting for prompt: $prompt_pattern" fi return fi done # No pattern matched, brief pause sleep 0.5 } # Load config file if it exists SCRIPT_DIR=$(dirname "$0") SCRIPT_NAME=$(basename "$0" .sh) CONFIG_FILE="${SCRIPT_DIR}/${SCRIPT_NAME}.conf" if [ -f "$CONFIG_FILE" ]; then echo "Loading config from $CONFIG_FILE" source "$CONFIG_FILE" else echo "Config file $CONFIG_FILE not found, generating template..." cat > "$CONFIG_FILE" << 'EOF' # tmux-oneshot.conf # Configuration file for tmux-oneshot.sh # Session name (leave empty to use first word of command) SESSION="" # For multiple commands, use an array: # COMMANDS=("ssh root@server" "sudo su" "password123") COMMANDS=() # Whether to attach to session after running command (0 or 1) ATTACH_SESSION=0 EOF echo "Generated $CONFIG_FILE with default values. Please edit and run again." exit 0 fi # Validate required variables if [ -z "$SESSION" ] && [ ${#COMMANDS[@]} -eq 0 ]; then echo "Error: Either SESSION or COMMANDS must be set in $CONFIG_FILE" >&2 exit 1 fi # Use command line arguments if provided, otherwise use config if [ $# -gt 0 ]; then COMMANDS=("$*") echo "Using command line arguments: $*" else if [ ${#COMMANDS[@]} -eq 0 ]; then echo "Error: No commands provided and no commands set in config" >&2 exit 1 fi echo "Using config commands: ${COMMANDS[*]}" fi # Use session name from config, or first word of first command if not set if [ -z "$SESSION" ]; then SESSION=$(echo "${COMMANDS[0]}" | awk '{print $1}') fi # Create session if missing if ! tmux has-session -t $SESSION 2>/dev/null; then echo "Creating tmux session: $SESSION" tmux new-session -d -s $SESSION else echo "Session $SESSION exists, reusing..." fi # Send commands individually with proper timing echo "Running commands: ${COMMANDS[*]}" for i in "${!COMMANDS[@]}"; do cmd="${COMMANDS[$i]}" echo "Running: $cmd" tmux send-keys -t $SESSION "$cmd" C-m # Only wait if there is a subsequent command if [ $i -lt $((${#COMMANDS[@]} - 1)) ]; then # Wait for command to complete or prompt for input with timeout wait_for_prompt "$cmd" fi done if [ $ATTACH_SESSION -eq 1 ]; then echo "Attaching to tmux session: $SESSION" tmux attach -t $SESSION fi