2009-10-13 18 views
6

Ho trovato un piccolo programma che mi permetterà di aggiungere GUI user-friendly ai miei script di Bash;Script BASH: selezione file whiptail

whiptail

Tuttavia il whiptail man page non è poi così utile e non fornisce alcun esempio. Dopo aver fatto alcune ricerche su Google ho capito come creare un semplice sì/no menu utilizzando whiptail:

#! /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 

Ma quello che mi piacerebbe davvero per costruire un menu di selezione file utilizzando whiptail per sostituire qualche vecchio codice che ho in pochi diversi backup/restore script bash che ho:

#!/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}" 

Presumo che ciò deve essere fatto tramite l'opzione '--menu' di Whiptail, ma io non sono sicuro di come andare a questo proposito? Eventuali puntatori? Oppure puoi indicarmi la direzione di alcuni esempi whiptail?

+0

Ho apportato una piccola modifica alla mia risposta (la formula di conversione ottale). –

risposta

8

Costruire una serie di nomi di file e di menu selezionare Etichette:

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 metodo come questo funzionerà anche se non ci sono nomi di file con spazi. Se il numero di file è elevato, potresti dover escogitare un'altra strategia di tag.

L'utilizzo di caratteri alfa per i tag consente di premere una lettera per passare all'elemento. I tag numerici non sembrano farlo. Se non ti serve quel comportamento, puoi eliminare una certa complessità.

Visualizzare il menu:

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

Se il codice di uscita è 255, la finestra di dialogo è stata annullata.

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

Per catturare la selezione in una variabile, utilizzare questa struttura (sostituire il vostro comando whiptail per "whiptail-comando"):

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

O

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

La variabile $result sarà contenere una lettera dell'alfabeto che corrisponde a un file nell'array. Sfortunatamente, Bash precedente alla versione 4 non supporta gli array associativi. È possibile calcolare l'indice nella matrice del file dalla lettera come questa (notare la singola citazione "extra"):

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

Esempio:

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

Nota: ho modificato la mia risposta per sostituire la precedente formula di conversione ottale che era ( quasi) completamente sbagliata. –

+0

Per i file temporanei è possibile utilizzare mktemp. Ad esempio, mytempfile=$(mktemp) ; echo "Hello world">$mytempfile; echo Contents of ${mytempfile}: $(cat $mytempfile) ; rm -f $mytempfile jbatista

+0

@jbatista: È vero, ma come è applicabile? Non si fa menzione di file temporanei qui. –

3

Whiptail è una leggera reimplementazione delle funzionalità più popolari di dialog, utilizzando Newt library. Ho fatto un rapido controllo e molte funzionalità di Whiptail sembrano comportarsi come le loro controparti nel dialogo. Quindi, un tutorial di dialogo dovrebbe iniziare. Puoi trovarne uno here ma Google è tuo amico, ovviamente. D'altra parte, lo extended example probabilmente contiene molta ispirazione per il tuo problema.

0

Ho provato in seguito, che ha funzionato:

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

si potrebbe cambiare questo in un multiplo-liner così, ho aggiunto il controllo di elenco vuoto:

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 

è necessario per regolare i numeri al fine di ottenere un'interfaccia pulita. E puoi sostituire lo "-" con qualsiasi altra cosa, se lo desideri. Ma se non lo fai, vedrai 2 voci per riga.

A proposito: la voce selezionata viene stampata su stderr.

Questo potrebbe richiedere un miglioramento in più, ma per un'idea di base penso sia sufficiente.

0

Questo sembra essere uno dei top risultati quando si cerca whiptail e nessuno dei risultati precedenti ha funzionato per me. Questo è quello che ho terminato 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" 

$ il risultato sarà vuoto se non è stata effettuata alcuna selezione valida. Ho aggiunto una selezione fittizia nella parte superiore dell'elenco che restituisce una stringa vuota come risultato, in modo che tu non accidentalmente selezioni il file sbagliato accidentalmente premendo Invio subito dopo la comparsa del menu. Se non lo vuoi, allora nella riga "for" rimuovi il +2 in "do j = $ ((2 * $ i + 2))" e anche le seguenti due righe che impostano un [0] e un [1] esplicitamente.

La cosa confusa su whiptail è che quando si legge da una matrice in una situazione come questa, si aspetta due elementi di dati per riga, entrambi visualizzati, il primo è il risultato che si desidera restituire se la linea è prevista (quale in alcune situazioni potrebbe essere una lettera o un numero) e il secondo è qualsiasi testo descrittivo che si possa desiderare. Ecco perché per la prima riga uso un [0] per dare una stringa vuota come risultato, e un [1] come testo descrittivo, ma da lì sul primo elemento della coppia contiene il nome file (che è quello che effettivamente ho voglio restituito) e il secondo è una stringa vuota, dal momento che non voglio visualizzare alcun testo diverso dal nome file su quelle righe.

anche un precedente post detto whiptail ha restituito un codice di errore di 255 se il pulsante di annullamento è stato premuto, ma che non era il caso per la versione che ho - restituisce 1. Così ho solo banco di prova per un codice di errore 0 e se suppongo che possa essere una voce valida, allora cerco per una lunghezza di stringa valida (oltre il numero di caratteri nell'estensione del file, incluso il carattere.).