Add tmux scripts
This commit is contained in:
153
tmux-daemon.sh
Normal file
153
tmux-daemon.sh
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# tmux-daemon.sh
|
||||||
|
# Idempotent tmux daemon manager with config file support
|
||||||
|
|
||||||
|
# Load config file if it exists
|
||||||
|
SCRIPT_DIR=$(dirname "$0")
|
||||||
|
SCRIPT_NAME=$(basename "$0" .sh)
|
||||||
|
CONFIG_FILE="${SCRIPT_DIR}/${SCRIPT_NAME}.sh.conf"
|
||||||
|
if [ ! -f "$CONFIG_FILE" ]; then
|
||||||
|
CONFIG_FILE="${SCRIPT_DIR}/${SCRIPT_NAME}.conf"
|
||||||
|
fi
|
||||||
|
if [ -f "$CONFIG_FILE" ]; then
|
||||||
|
echo "Loading config from $CONFIG_FILE"
|
||||||
|
source "$CONFIG_FILE"
|
||||||
|
else
|
||||||
|
CONFIG_FILE="${SCRIPT_DIR}/${SCRIPT_NAME}.sh.conf"
|
||||||
|
echo "Config file $CONFIG_FILE not found, generating template..."
|
||||||
|
cat > "$CONFIG_FILE" << 'EOF'
|
||||||
|
# tmux-daemon.conf
|
||||||
|
# Configuration file for tmux-daemon.sh
|
||||||
|
|
||||||
|
# Session name
|
||||||
|
SESSION="example"
|
||||||
|
|
||||||
|
# Whether to attach to session after setup (0 or 1)
|
||||||
|
ATTACH_SESSION=0
|
||||||
|
|
||||||
|
# Commands to run (array format)
|
||||||
|
# Format: "workdir:::command" OR just "command"
|
||||||
|
CMDS=(
|
||||||
|
"ping google.com"
|
||||||
|
"ping google.com"
|
||||||
|
"ping google.com"
|
||||||
|
"ping google.com"
|
||||||
|
"ping google.com"
|
||||||
|
"ping google.com"
|
||||||
|
"ping google.com"
|
||||||
|
)
|
||||||
|
EOF
|
||||||
|
echo "Generated $CONFIG_FILE with default values. Please edit and run again."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate required variables
|
||||||
|
if [ -z "$SESSION" ]; then
|
||||||
|
echo "Error: SESSION must be set in $CONFIG_FILE" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ${#CMDS[@]} -eq 0 ]; then
|
||||||
|
echo "Error: CMDS array must be set in $CONFIG_FILE" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[main] SESSION: $SESSION"
|
||||||
|
echo "[main] Commands: ${CMDS[*]}"
|
||||||
|
|
||||||
|
# Create session if missing
|
||||||
|
if ! tmux has-session -t $SESSION 2>/dev/null; then
|
||||||
|
echo "[main] Creating tmux session: $SESSION"
|
||||||
|
tmux new-session -d -s $SESSION -n win0
|
||||||
|
else
|
||||||
|
echo "[main] Session $SESSION exists, reusing..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
win=0
|
||||||
|
pane=0
|
||||||
|
|
||||||
|
for i in "${!CMDS[@]}"; do
|
||||||
|
entry="${CMDS[$i]}"
|
||||||
|
echo "[loop:$i] entry: $entry"
|
||||||
|
if [[ "$entry" == *":::"* ]]; then
|
||||||
|
workdir="${entry%%:::*}"
|
||||||
|
echo "[loop:$i] workdir set from entry: $workdir"
|
||||||
|
cmd="${entry#*:::}"
|
||||||
|
echo "[loop:$i] cmd set from entry: $cmd"
|
||||||
|
else
|
||||||
|
workdir="$PWD"
|
||||||
|
echo "[loop:$i] workdir set to PWD: $workdir"
|
||||||
|
cmd="$entry"
|
||||||
|
echo "[loop:$i] cmd set to entry: $cmd"
|
||||||
|
fi
|
||||||
|
echo "[loop:$i] Processing command: $cmd (workdir: $workdir)"
|
||||||
|
|
||||||
|
# Determine target window/pane
|
||||||
|
win=$((i / 4))
|
||||||
|
echo "[loop:$i] win updated: $win"
|
||||||
|
pane=$((i % 4))
|
||||||
|
echo "[loop:$i] pane updated: $pane"
|
||||||
|
|
||||||
|
# Create window if missing
|
||||||
|
if ! tmux list-windows -t $SESSION | grep -q "^$win:"; then
|
||||||
|
echo "[loop:$i] Creating window $win"
|
||||||
|
tmux new-window -t $SESSION:$win -n win$win
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get current pane count in window
|
||||||
|
panes=($(tmux list-panes -t $SESSION:$win -F '#P'))
|
||||||
|
echo "[loop:$i] panes in window $win: ${panes[*]}"
|
||||||
|
|
||||||
|
# Create missing pane if needed
|
||||||
|
if [ $pane -ge ${#panes[@]} ]; then
|
||||||
|
echo "[loop:$i] Splitting pane $((pane-1)) to create pane $pane in window $win"
|
||||||
|
if [ $pane -eq 1 ]; then
|
||||||
|
tmux split-window -h -t $SESSION:$win
|
||||||
|
elif [ $pane -eq 2 ]; then
|
||||||
|
tmux split-window -v -t $SESSION:$win
|
||||||
|
elif [ $pane -eq 3 ]; then
|
||||||
|
tmux split-window -v -t $SESSION:$win.1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Always apply appropriate layout based on current pane count
|
||||||
|
current_panes=($(tmux list-panes -t $SESSION:$win -F '#P'))
|
||||||
|
if [ ${#current_panes[@]} -eq 2 ]; then
|
||||||
|
tmux select-layout -t $SESSION:$win even-horizontal
|
||||||
|
else
|
||||||
|
tmux select-layout -t $SESSION:$win tiled
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if command is already running in the pane
|
||||||
|
running=$(tmux list-panes -t $SESSION:$win -F '#{pane_current_command}' | sed -n "$((pane+1))p")
|
||||||
|
echo "[loop:$i] running in pane $pane: $running"
|
||||||
|
if [[ "$running" == "$(basename "$cmd" | awk '{print $1}')" ]]; then
|
||||||
|
echo "[loop:$i] Command already running in pane $pane, skipping..."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create temporary script to run command in auto-restart loop
|
||||||
|
tmpfile=$(mktemp)
|
||||||
|
echo "[loop:$i] tmpfile created: $tmpfile"
|
||||||
|
workdir_escaped=$(printf %q "$workdir")
|
||||||
|
{
|
||||||
|
printf '#!/bin/bash\n'
|
||||||
|
printf 'cd %s || exit 1\n' "$workdir_escaped"
|
||||||
|
printf 'while true; do\n'
|
||||||
|
printf " echo '[tmux-daemon] Starting: %s (in %s)'\n" "$cmd" "$workdir"
|
||||||
|
printf ' %s\n' "$cmd"
|
||||||
|
printf " echo '[tmux-daemon] Command exited with code \$?']\n"
|
||||||
|
printf ' sleep 2\n'
|
||||||
|
printf 'done\n'
|
||||||
|
} >"$tmpfile"
|
||||||
|
chmod +x "$tmpfile"
|
||||||
|
echo "[loop:$i] Sending command to pane $pane in window $win"
|
||||||
|
tmux send-keys -t $SESSION:$win.$pane "$tmpfile" C-m
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "[main] Done."
|
||||||
|
|
||||||
|
if [ $ATTACH_SESSION -eq 1 ]; then
|
||||||
|
echo "[main] Attaching to tmux session: $SESSION"
|
||||||
|
tmux attach -t $SESSION
|
||||||
|
fi
|
||||||
117
tmux-oneshot.sh
Normal file
117
tmux-oneshot.sh
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
#!/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:10"
|
||||||
|
"sudo*:Password|password|\\[sudo\\] password for:10"
|
||||||
|
"su*:Password|password:10"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 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}.sh.conf"
|
||||||
|
if [ ! -f "$CONFIG_FILE" ]; then
|
||||||
|
CONFIG_FILE="${SCRIPT_DIR}/${SCRIPT_NAME}.conf"
|
||||||
|
fi
|
||||||
|
if [ -f "$CONFIG_FILE" ]; then
|
||||||
|
echo "Loading config from $CONFIG_FILE"
|
||||||
|
source "$CONFIG_FILE"
|
||||||
|
else
|
||||||
|
CONFIG_FILE="${SCRIPT_DIR}/${SCRIPT_NAME}.sh.conf"
|
||||||
|
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
|
||||||
|
|
||||||
|
# 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"
|
||||||
|
tmpfile=$(mktemp)
|
||||||
|
{
|
||||||
|
printf '#!/bin/bash\n'
|
||||||
|
printf '%s\n' "$cmd"
|
||||||
|
} >"$tmpfile"
|
||||||
|
chmod +x "$tmpfile"
|
||||||
|
tmux send-keys -t $SESSION -l "$tmpfile"
|
||||||
|
tmux send-keys -t $SESSION Enter
|
||||||
|
# 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
|
||||||
Reference in New Issue
Block a user