2009-10-13 21 views
6

He encontrado un gran pequeño programa que me permitirá agregar GUI fáciles de usar a mis Bash Scripts;Scripts BASH: archivo whiptail seleccione

whiptail

Sin embargo, el whiptail man page no es tan útil y no proporciona ningún ejemplo. Después de hacer algunas búsquedas de Google entiendo cómo crear un simple sí/no menú utilizando cola de látigo:

#! /bin/bash 
# http://archives.seul.org/seul/project/Feb-1998/msg00069.html 
if (whiptail --title "PPP Configuration" --backtitle "Welcome to SEUL" --yesno " 
Do you want to configure your PPP connection?" 10 40) 
then 
     echo -e "\nWell, you better get busy!\n" 
elif (whiptail --title "PPP Configuration" --backtitle "Welcome to 
SEUL" --yesno "   Are you sure?" 7 40) 
     then 
       echo -e "\nGood, because I can't do that yet!\n" 
     else 
       echo -e "\nToo bad, I can't do that yet\n" 
fi 

Pero lo que realmente me gustaría construir un menú de selección de archivos utilizando cola de látigo para reemplazar algo viejo código que tengo en unos pocos diferentes de copia de seguridad/restauración scripts bash que tienen:

#!/bin/bash 
#This script allows you to select a file ending in the .tgz extension (in the current directory) 
echo "Please Select the RESTORE FILE you would like to restore: " 
    select RESTOREFILE in *.tgz; do 
    break #Nothing 
    done 
echo "The Restore File you selected was: ${RESTOREFILE}" 

asumo que esto tiene que ser hecho a través de la opción '--menu' de cola de látigo, pero no estoy seguro de cómo hacerlo? ¿Alguna sugerencia? ¿O puede indicarme algunos ejemplos de whiptail?

+0

He realizado un pequeño cambio en mi respuesta (la fórmula de conversión octal). –

Respuesta

8

Construir una matriz de nombres de archivos y seleccione del menú etiquetas:

i=0 
s=65 # decimal ASCII "A" 
for f in *.tgz 
do 
    # convert to octal then ASCII character for selection tag 
    files[i]=$(echo -en "\0$(($s/64 * 100 + $s % 64/8 * 10 + $s % 8))") 
    files[i+1]="$f" # save file name 
    ((i+=2)) 
    ((s++)) 
done 

Un método como este funcionará incluso si hay nombres de archivo con espacios. Si la cantidad de archivos es grande, puede que tenga que diseñar otra estrategia de etiquetas.

El uso de caracteres alfabéticos para las etiquetas le permite presionar una letra para saltar al elemento. Las etiquetas numéricas no parecen hacer eso. Si no necesitas ese comportamiento, entonces puedes eliminar algo de complejidad.

visualización del menú:

whiptail --backtitle "Welcome to SEUL" --title "Restore Files" \ 
    --menu "Please select the file to restore" 14 40 6 "${files[@]}" 

Si el código de salida es 255, el diálogo fue cancelada.

if [[ $? == 255 ]] 
then 
    do cancel stuff 
fi 

Para la captura de la selección en una variable, utilice esta estructura (sustituya su comando whiptail de "cola de látigo-comando"):

result=$(whiptail-command 2>&1 >/dev/tty) 

O

result=$(whiptail-command 3>&2 2>&1 1>&3-) 

La variable $result se contiene una letra del alfabeto que corresponde a un archivo en la matriz. Desafortunadamente, Bash anterior a la versión 4 no admite matrices asociativas. Se puede calcular el índice en la matriz del archivo de la carta como esta (nótese la "extra" comilla simple):

((index = 2 * ($(printf "%d" "'$result") - 65) + 1)) 

Ejemplo:

Welcome to SEUL 
       ┌──────────┤ Restore Files ├───────────┐ 
       │ Please select the file to restore │ 
       │          │ 
       │   A one.tgz  ↑   │ 
       │   B two.tgz  ▮   │ 
       │   C three.tgz ▒   │ 
       │   D another.tgz ▒   │ 
       │   E more.tgz  ▒   │ 
       │   F sp ac es.tgz ↓   │ 
       │          │ 
       │          │ 
       │  <Ok>   <Cancel>  │ 
       │          │ 
       └──────────────────────────────────────┘ 
+0

Tenga en cuenta: He editado mi respuesta para reemplazar la fórmula de conversión octal anterior que era ( casi) completamente incorrecta. –

+0

Para archivos temporales, puede usar mktemp. Por ejemplo, mytempfile=$(mktemp) ; echo "Hello world">$mytempfile; echo Contents of ${mytempfile}: $(cat $mytempfile) ; rm -f $mytempfile jbatista

+0

@jbatista: Es cierto, pero ¿cómo es aplicable? No hay mención de archivos temporales aquí. –

3

Whiptail es una reimplementación ligera de las características más populares de dialog, usando el Newt library. Hice una comprobación rápida, y muchas características en Whiptail parecen comportarse como sus contrapartes en el diálogo. Entonces, un tutorial de diálogo debería comenzar. Puede encontrar uno here pero Google es su amigo, por supuesto. Por otro lado, el extended example probablemente contenga mucha inspiración para su problema.

0

He tratado siguiente, que trabajó:

whiptail --title "PPP Config" --backtitle "Welcome to SEUL" --menu YourTitle 20 80 10 `for x in $(ls -1 *.tgz); do echo $x "-"; done` 

es posible cambiar esto en un múltiplo-liner, así, he añadido la comprobación de lista vacía:

MYLIST=`for x in $(ls -1 *.tgz); do echo $x "-"; done` 
WC=`echo $MYLIST | wc -l` 

if [[WC -ne 0]]; then 
    whiptail --title "PPP Config" --backtitle "Welcome to SEUL" --menu YourTitle 20 80 10 $MYLIST 
fi 

que necesita para ajustar los números para obtener una interfaz limpia. Y puede reemplazar el "-" por cualquier otra cosa si lo desea. Pero si no lo hace, verá 2 entradas por línea.

Por cierto: la entrada seleccionada se imprime en stderr.

Esto podría necesitar mejorar un poco más, pero para una idea básica, creo que es suficiente.

0

Este parece ser uno de los mejores resultados cuando buscas whiptail, y ninguno de los resultados anteriores funcionó para mí. Esto es lo que terminé usando:

#! /bin/bash 
shopt -s nullglob 
dir=`pwd` 
cd /path/to/files 
arr=(*.tgz) 
for ((i=0; i<${#arr[@]}; i++)); do j=$((2*$i+2)); a[j]="${arr[$i]}"; a[j+1]=""; done 
a[0]="" 
# Next line has extra spaces at right to try to center it: 
a[1]="Please make a selection from the files below              " 
result=$(whiptail --ok-button "OK button text" --cancel-button "Cancel Button Text" --title "Title Text" --backtitle "Text at upper left corner of page" --menu "Menu Text (not used??)" 30 160 24 "${a[@]}" 2>&1 >/dev/tty) 
if [[ $? = 0 ]] 
then 
# ge 5 in next line should be length of file extension including . character, plus 1 
    [ ${#result} -ge 5 ] && outfile="/path/to/files/$result" || echo "Selection not made" 
fi 
cd "$dir" 

$ resultado estará vacío si no se realizó una selección válida. Agregué una selección ficticia en la parte superior de la lista que devuelve una cadena vacía como resultado, para que no seleccione accidentalmente el archivo incorrecto al presionar accidentalmente Enter justo después de que aparezca el menú. Si no quiere eso, en la línea "para" elimine el +2 en "do j = $ ((2 * $ i + 2))" y también las dos líneas siguientes que establecen un [0] y un [1] explícitamente.

Lo confuso de whiptail es que cuando se lee desde una matriz en una situación como esta, se esperan dos elementos de datos por línea, los cuales se muestran, el primero es el resultado que se desea devolver si se espera la línea (que en algunas situaciones puede ser una letra o un número) y el segundo es cualquier texto descriptivo que desee. Es por eso que para la primera línea uso un [0] para dar como resultado una cadena vacía y un [1] como texto descriptivo, pero a partir de ahí el primer elemento del par contiene el nombre del archivo (que es lo que realmente quiere devuelto) y el segundo es una cadena vacía, ya que no quiero mostrar ningún texto que no sea el nombre del archivo en esas líneas.

También una publicación anterior dicho whiptail devolvió un código de error de 255 si se presionó el botón cancelar, pero ese no fue el caso para la versión que tengo - devuelve 1. Así que solo prueba un código de error de 0 y si es así, supongo que puede ser una entrada válida, entonces pruebo una longitud de cadena válida (más que el número de caracteres en la extensión de archivo, incluido el carácter.) para estar seguro.

Cuestiones relacionadas