Creación de ventanas interactivas en terminal con dialog, whiptail y ncurses
Las interfaces de usuario basadas en texto (TUI) son una alternativa poderosa a las GUI gráficas, especialmente en entornos de servidor o cuando se necesita ligereza. Este manual cubre las herramientas más populares para crear TUI en Linux.
sudo apt-get install dialog whiptail ncurses-utils libncurses-dev python3
sudo yum install dialog whiptail ncurses ncurses-devel python3
sudo pacman -S dialog whiptail ncurses python
dialog --title "Título" --msgbox "Este es un mensaje" 10 30
dialog --title "Confirmación" --yesno "¿Desea continuar?" 10 30
if [ $? -eq 0 ]; then
echo "Usuario dijo Sí"
else
echo "Usuario dijo No"
fi
dialog --title "Entrada" --inputbox "Introduce tu nombre:" 10 30 2>nombre.txt
nombre=$(cat nombre.txt)
dialog --title "Seguridad" --insecure --passwordbox "Contraseña:" 10 30 2>pass.txt
dialog --title "Menú Principal" --menu "Elige una opción:" 15 40 10 \
1 "Opción 1" \
2 "Opción 2" \
3 "Opción 3" 2>opcion.txt
dialog --title "Software" --checklist "Selecciona paquetes:" 15 40 5 \
1 "Python" off \
2 "Node.js" on \
3 "Go" off 2>paquetes.txt
dialog --title "S.O." --radiolist "Elige un sistema:" 15 40 5 \
1 "Linux" on \
2 "Windows" off \
3 "MacOS" off 2>os.txt
Whiptail es compatible con dialog pero con menos características y más ligero.
whiptail --title "Ejemplo" --msgbox "Este es un mensaje" 10 30
whiptail --title "Menú" --menu "Elige:" 15 40 5 1 "Uno" 2 "Dos" 3 "Tres"
NCurses es una biblioteca para desarrollo de interfaces en terminal con control completo sobre la pantalla.
#!/bin/bash # Configuración inicial clear tput civis # Oculta cursor # Dibuja ventana tput cup 5 10 echo -e "\e[44m\e[37m┌──────────────────────────────┐" tput cup 6 10 echo -e "│ \e[1mMENÚ PRINCIPAL\e[0m\e[44m\e[37m │" tput cup 7 10 echo -e "├──────────────────────────────┤" tput cup 8 10 echo -e "│ \e[33m1)\e[0m Opción 1 │" tput cup 9 10 echo -e "│ \e[33m2)\e[0m Opción 2 │" tput cup 10 10 echo -e "│ \e[33m3)\e[0m Salir │" tput cup 11 10 echo -e "└──────────────────────────────┘\e[0m" # Espera entrada tput cup 13 10 read -p "Selecciona una opción [1-3]: " opcion # Restaura terminal tput cnorm # Muestra cursor clear
import curses
def main(stdscr):
# Configuración inicial
curses.curs_set(0) # Oculta cursor
stdscr.clear()
# Configura colores
curses.start_color()
curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE)
curses.init_pair(2, curses.COLOR_YELLOW, curses.COLOR_BLACK)
# Dibuja ventana
stdscr.bkgd(curses.color_pair(1))
stdscr.border()
# Título
title = "MENÚ PRINCIPAL"
stdscr.addstr(2, (curses.COLS - len(title)) // 2, title, curses.A_BOLD)
# Opciones
options = ["1) Opción 1", "2) Opción 2", "3) Salir"]
for i, option in enumerate(options):
stdscr.addstr(5 + i, 10, option, curses.color_pair(2))
# Resaltar selección
current_row = 0
while True:
stdscr.addstr(5 + current_row, 10, options[current_row],
curses.color_pair(2) | curses.A_REVERSE)
key = stdscr.getch()
stdscr.addstr(5 + current_row, 10, options[current_row], curses.color_pair(2))
if key == curses.KEY_UP and current_row > 0:
current_row -= 1
elif key == curses.KEY_DOWN and current_row < len(options) - 1:
current_row += 1
elif key == curses.KEY_ENTER or key in [10, 13]:
break
return current_row
if __name__ == "__main__":
print(f"Seleccionaste: {curses.wrapper(main) + 1}")
Para crear efectos visuales avanzados:
echo -e "\e[37m╔════════════════════════╗" echo -e "║ \e[36mTítulo de la ventana\e[37m ║" echo -e "╠════════════════════════╣" echo -e "║ \e[0mContenido aquí... \e[37m║" echo -e "╚════════════════════════╝\e[0m"
echo -e "\e[37m┌────────────────────┐\e[90m▒▒▒" echo -e "\e[37m│ \e[36mContenido \e[37m│\e[90m▒▒▒" echo -e "\e[37m└────────────────────┘\e[90m▒▒▒" echo -e " ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒\e[0m"
dialog --title "Con Ratón" --msgbox "Prueba a hacer clic" 10 30 --mouse
import curses
def main(stdscr):
curses.mousemask(curses.ALL_MOUSE_EVENTS)
while True:
key = stdscr.getch()
if key == curses.KEY_MOUSE:
_, x, y, _, _ = curses.getmouse()
stdscr.addstr(y, x, "X")
#!/bin/bash
# Instalador ejemplo con dialog
# Verificar dependencias
if ! command -v dialog &> /dev/null; then
echo "Instalando dialog..."
sudo apt-get install -y dialog
fi
# Menú principal
while true; do
choice=$(dialog --title "Instalador de Software" \
--menu "Elige una opción:" 15 50 10 \
1 "Instalar paquetes básicos" \
2 "Configurar sistema" \
3 "Realizar copia de seguridad" \
4 "Salir" 3>&1 1>&2 2>&3)
case $choice in
1)
packages=$(dialog --title "Instalación" \
--checklist "Selecciona paquetes:" 20 50 10 \
python "Python 3" on \
nodejs "Node.js" off \
golang "Go Language" off 3>&1 1>&2 2>&3)
if [ -n "$packages" ]; then
sudo apt-get install -y $packages
dialog --msgbox "Paquetes instalados correctamente" 10 30
fi
;;
2)
hostname=$(dialog --title "Configuración" \
--inputbox "Nuevo nombre de host:" 10 30 3>&1 1>&2 2>&3)
if [ -n "$hostname" ]; then
sudo hostnamectl set-hostname "$hostname"
dialog --msgbox "Hostname cambiado a $hostname" 10 30
fi
;;
3)
backup_dir=$(dialog --title "Copia de seguridad" \
--dselect "$HOME" 15 50 3>&1 1>&2 2>&3)
if [ -n "$backup_dir" ]; then
tar -czf "$backup_dir/backup_$(date +%F).tar.gz" "$HOME"
dialog --msgbox "Copia de seguridad completada en $backup_dir" 10 50
fi
;;
4)
break
;;
esac
done
clear
echo "Instalación completada"
#!/bin/bash
# Dashboard de sistema con NCurses
# Configuración inicial
clear
tput civis
trap 'tput cnorm; clear' EXIT
# Colores
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
YELLOW=$(tput setaf 3)
BLUE=$(tput setaf 4)
RESET=$(tput sgr0)
REVERSE=$(tput rev)
# Tamaño de pantalla
rows=$(tput lines)
cols=$(tput cols)
# Actualizar dashboard
update_display() {
# Obtener información del sistema
local cpu_usage=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')
local mem_usage=$(free -m | awk '/Mem:/ {printf "%.1f", $3/$2*100}')
local disk_usage=$(df -h / | awk '/\// {print $5}')
local uptime=$(uptime -p)
local hostname=$(hostname)
# Dibujar interfaz
clear
# Marco
tput cup 0 0
echo -e "${BLUE}╔════════════════════════════════════════════════════════════════╗"
for i in $(seq 1 $((rows-3))); do
tput cup $i 0; echo -e "║${RESET} ${BLUE}║"
done
tput cup $((rows-2)) 0
echo -e "╠════════════════════════════════════════════════════════════════╣"
tput cup $((rows-1)) 0
echo -e "║ ${YELLOW}Q${RESET}:Salir ${YELLOW}R${RESET}:Actualizar ${BLUE}║"
echo -e "╚════════════════════════════════════════════════════════════════╝${RESET}"
# Contenido
tput cup 2 5; echo -e "${REVERSE} DASHBOARD DEL SISTEMA ${RESET}"
tput cup 4 5; echo -e "${GREEN}Hostname:${RESET} $hostname"
tput cup 5 5; echo -e "${GREEN}Uptime:${RESET} $uptime"
# CPU
tput cup 7 5; echo -e "${BLUE}CPU Usage:${RESET}"
tput cup 7 20; printf "[%5.1f%%] " $cpu_usage
local cpu_bar=$(( (cols-30) * cpu_usage / 100 ))
printf "${GREEN}%${cpu_bar}s${RESET}${RED}%$((cols-30-cpu_bar))s${RESET}" "" "" | tr ' ' '='
# Memoria
tput cup 9 5; echo -e "${BLUE}Mem Usage:${RESET}"
tput cup 9 20; printf "[%5.1f%%] " $mem_usage
local mem_bar=$(( (cols-30) * mem_usage / 100 ))
printf "${GREEN}%${mem_bar}s${RESET}${RED}%$((cols-30-mem_bar))s${RESET}" "" "" | tr ' ' '='
# Disco
tput cup 11 5; echo -e "${BLUE}Disk Usage (root):${RESET}"
tput cup 11 25; printf "[%5s] " "$disk_usage"
local disk_value=${disk_usage%\%}
local disk_bar=$(( (cols-35) * disk_value / 100 ))
printf "${GREEN}%${disk_bar}s${RESET}${RED}%$((cols-35-disk_bar))s${RESET}" "" "" | tr ' ' '='
# Procesos
tput cup 13 5; echo -e "${BLUE}Top Processes:${RESET}"
local proc_line=15
ps -eo pid,user,pcpu,pmem,comm --sort=-pcpu | head -6 | tail -5 | while read -r line; do
tput cup $proc_line 5; echo "$line"
((proc_line++))
done
}
# Bucle principal
while true; do
update_display
# Esperar entrada
read -t 5 -n 1 key
case $key in
q|Q) break ;;
r|R) continue ;;
*) sleep 1 ;;
esac
done
clear