[BASH] Elegir opcion de un menu sin presionar tecla intro

Iniciado por Hekaly, 23 Enero 2014, 22:00 PM

0 Miembros y 1 Visitante están viendo este tema.

Hekaly

Buenas a todos.

Estoy realizando un script en el que uso menus. El caso es que lo normal es que pongamos las opciones sea como sea (echos, select-case, ps3, etc) y por ultimo ponemos un read para capturar en variable lo que mete el usuario y el script va a la direccion que sea.

El uso de estos tipos de script es que nesesitas poner el numero de opcion o el nombre o lo que sea y luego dar a la tecla intro.

Mi preguta es si bash permite seleccionar opciones de menu directamente pulsando la letra sin pasar por intro, es decir, si el menu tiene tres opciones y presiono dos, que automaticamente vaya a la parte dos.

Es por decirlo asi el equivalente al comando antiguo de windows choice para hacer menus.

Muchas gracias por la ayuda.

Yoel Alejandro

Eso se llama poner el teclado en "modo POSIX no estándar", o modo RAW. Yo lo se hacer en C, pero no lo he intentado en BASH (aunque no debe ser difícil). Lo que pasa es que el estándar POSIX establece que la entrada de teclado se realiza presionando ENTER al final, pero LINUX tiene la opción de pasar a modo no-estándar o modo RAW (crudo).

Usando algo que se llama ioctl's se puede hacer, hay un servicio que te permite establecer el modo del teclado. Ahora si quieres un código en C que lea directamente la tecla pulsada, o más precisamente una versión para LINUX de la función getch() de Borland, aquí tienes este:


char getch(void) {

int c;
struct termios p, old_p;
int fd;
int n_bytes;
FILE *fPtr;

// rescar la estructura de configuración termios, con tcgetattr()
// (save the termios configuration struct, with tcgetattr())
tcgetattr(STDINFD, &old_p);
 
/* activar modo RAW
   (activate RAW mode) */
p = old_p;
cfmakeraw(&p);

/* pasar los nuevos paramentros
   (pass the new parameters) */
tcsetattr(STDINFD, TCSANOW, &p);

/* leer un caracter del búfer y asignarlo a c
   (read a character from buffer, and asign it to c) */
fd = open("/dev/console", O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0) {
perror("open");
return -1;
}

fflush(stdin);
fflush(stdout);
fflush(stderr);

/* aquí lee el carácter y lo deposita en c */
read(STDINFD, &c, sizeof(char))

// restablecemos la struct termios, con tcsetattr
// (restore the termios struct, with tcsetattr)
tcsetattr(STDINFD, TCSANOW, &old_p);

close(fd);
return c;
}


Este código funciona y te devuelve el código ASCII de la tecla pulsada. Así puedes construir algo como:


c = getch( );
switch ( c ) {
case 1:
    /* hacer algo */
case 2:
    /* hacer algo */
}


Esto no es para BASH sino para C, entonces si lo quieres invocar desde BASH haz un ejecutable y lo invocas desde BASH.

P.D. 1) Hay soluciones directamente para BASH, creo que con el comando "stty", pero no lo conozco bien (aún).
2) Estoy casi seguro que el código de getch() que suministré aquí es redundante y se puede optimizar. No lo he hecho, sin embargo en esta forma tosca se que funciona así que lo puedes usar.
3) Debes ser propietario de la consola, o sea, del fichero especial /dev/console para poder usar este programa. En LINUX eso significa que, o ejecutas como root, o "setuidas" el programa, porque /dev/console tiene a root como propietario.
Saludos, Yoel.
P.D..-   Para mayores dudas, puedes enviarme un mensaje personal (M.P.)

Todo-System.

Para la funcion deseada es necesario pasarle al comando read, el parametro -n 1
para que reciva la entra de texto con solo un intento y sin confirmacion de la tecla
enter. Por ejemplo:

read -n 1 x

Donde x es l variable que toma el valor de la entrada del teclado