Whiptail Trucs et Astuces

Bonjour à tous,

Je re-poste un nouveau sujet sur whiptail pour ceux qui souhaitent faire du pseudo graphique pour des scripts interactifs sous Debian. Certains me diront que dialog est mieux et c’est vrai mais il n’est pas natif sous Debian !
J’invite les membres du forum qui s’intéressent à la question à poster leurs astuces à la suite de celles-ci. Comme ça on centralise et ce sera + simple pour ceux qui voudront se documenter.

Précautions oratoires

Avec whiptail pas d’install de paquet nécessaire pour exécuter le script (voir question en bas du post). Le portage sous sh ou ksh ne m’intéresse pas le moins du monde vu l’utilité que j’ai pour le script. Je l’ai rédigé sous bash car c’est en natif sous Debian. Je ne script pas sous les Red Hat Like et je n’aime pas trop Ubuntu, Mint, Fedora, Gentoo… Ne me jetez pas la pierre, chacun ses goûts. C’est sûr que pour OpenStack j’utilise Ubuntu mais si j’ai le choix je prends Debian. De même si on me commande un SRV exchange, pas le choix, c’est du CroSoft…

Contrôle de saisie !

J’ai fait un petit script qui permet d’ajouter un contrôle de saisie + une remontée vers la question précédente. Le principe c’est des fonctions gigognes qui permettent de revenir en arrière. Pas très élégant, mais qui dit mieux (@Dunatotatos) ? Si c’est plus simple et intelligible par moi je prends ! :smiley:

[code]function Quest1 () {
function testip () {
IP=$(whiptail --inputbox “Tapez l’adresse IPV4 que vous souhaitez assigner au serveur
(au format xxx.xxx.xxx.xxx ou x représente un chiffre) :” 20 80 $(ifconfig| grep “inet adr”| grep -v 127.0.0.1|awk ‘{print $2}’|cut -d: -f2) 3>&1 1>&2 2>&3)
if [ “$?” = “1” ]
then
Quest1
fi
}
testip
until [[ “$IP” =~ ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]]
do
testip
done

function Quest2 () {

function testmask () {
netmask=$(whiptail --inputbox “Tapez l’adresse du masque de sous reseau :” 20 80 $(ifconfig |grep Masque|grep Bcast|awk ‘{ print $4 }’|cut -d: -f2) 3>&1 1>&2 2>&3)
if [ “$?” = “1” ]
then
Quest1
fi
}
testmask
until [[ “$netmask” =~ ^((255|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]|0).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]]
do
testmask
done

function Quest3 () {

function testdns () {
dns=$(whiptail --inputbox “Tapez l’adresse du serveur DNS primaire :” 20 80 $(grep nameserver /etc/resolv.conf|head -n 1|awk ‘{ print $2 }’ ) 3>&1 1>&2 2>&3)
if [ “$?” = “1” ]
then
Quest2
fi
}
testdns
until [[ “$dns” =~ ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]]
do
testdns
done

function Quest4 () {

function testdns2 () {
dns2=$(whiptail --inputbox “Tapez l’adresse du serveur DNS secondaire :” 20 80 $(grep nameserver /etc/resolv.conf|head -2|tail -1|awk ‘{ print $2 }’ ) 3>&1 1>&2 2>&3)
if [ “$?” = “1” ]
then
Quest3
fi
}
testdns2
until [[ “$dns2” =~ ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]]
do

testdns2

done

function Quest5 () {

function testgate () {
##gateway=$(whiptail --inputbox “Tapez l’adresse de la passerelle :” 20 80 $(route|grep default|awk ‘{print $2}’) 3>&1 1>&2 2>&3)
GateW=$(route|grep default|awk ‘{print $2}’)

if [[ $GateW =~ [A-Z]$ ]] || [[ $GateW =~ [a-z]$ ]]
then
nslookup $GateW|grep Address|grep -v “#”|awk ‘{print $2}’ > /tmp/passerelle
gateway=$(whiptail --inputbox “Tapez l’adresse de la passerelle :” 20 80 $(cat /tmp/passerelle) 3>&1 1>&2 2>&3)
else
gateway=$(whiptail --inputbox “Tapez l’adresse de la passerelle :” 20 80 $(route|grep default|awk ‘{print $2}’) 3>&1 1>&2 2>&3)
fi
if [ “$?” = “1” ]
then
Quest4
fi
test -f /tmp/passerelle
if [ “$?” = “0” ]
then
rm /tmp/passerelle
fi

}
testgate
until [[ “$gateway” =~ ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]]
do
testgate
done

function Quest6 () {

function domaine_addr () {
domain=$(whiptail --inputbox “Tapez votre nom de domaine :” 20 80 $(grep domain /etc/resolv.conf|awk ‘{print $2}’) 3>&1 1>&2 2>&3)
if [ “$?” = “1” ]
then
Quest5
fi
}
domaine_addr
until [[ “$domain” =~ [A-Za-z0-9.-]+.[A-Za-z]{2,4}$ ]]
do
domaine_addr
done

function Quest7 () {

function hostname_addr () {
hostname=$(whiptail --inputbox “Tapez le nom de machine de votre serveur” 20 80 $(cat /etc/hostname) 3>&1 1>&2 2>&3)
if [ “$?” = “1” ]
then
Quest6
fi
}
hostname_addr
until [[ “$hostname” =~ ^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-][a-zA-Z0-9]).)([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])$ ]]
do
hostname_addr
done

}
}
}
}
}
}
}

Quest1
Quest2
Quest3
Quest4
Quest5
Quest6
Quest7

whiptail --msgbox “Récapitulatif des modifications :
- Adresse IP de l’interface : $IP
- Masque de sous réseau : $netmask
- Passerelle : $gateway
- Serveur DNS 1 : $dns
- Serveur DNS 2 :$dns2
- Nom de machine : $hostname
- Nom de domaine : $domain
- FQDN : $hostname.$domain” 20 80[/code]

Radiolist sur le contenu d’un dossier

j’ai créé un petit script pour lister le contenu d’un dossier et l’insérer dans un whiptail radiolist.
Le script n’est pas très propre, il y a sans aucun doute moyen de faire mieux, mais en tout cas ça fonctionne. Mais si quelqu’un connaît un moyen de faire mieux en 3 lignes et sous bash ça m’intéresse ! :smiley:

Astuce pour des fichiers et non des dossiers remplacer ^d (qui commence par d) par ^- (qui commence par -)

[code]##lister les dossiers contenus dans un dossier et insérer les valeurs trouvées dans un radiolist whiptail

mkdir /tmp/RADIO

Nb de dossiers

Dnum=$(ls -l /usr | grep -c ^d)

créer liste de dossiers à insérer dans le menu whiptail

ls -l /usr | grep ^d | awk ‘{print $9}’ > /tmp/RADIO/NbDir.txt

Ajout d’un " en fin de ligne

sed -i ‘s/$/"/’ /tmp/RADIO/NbDir.txt

Ajout d’un " en début de ligne (pas moyen de le faire sans le concaténer dans un fichier texte !!)

sed ‘s/^/ "/’ /tmp/RADIO/NbDir.txt > /tmp/RADIO/NbDir2.txt

On remet tout ensemble…

cat /tmp/RADIO/NbDir2.txt > /tmp/RADIO/NbDir.txt

On ajoute un \ en fin de ligne ==> opur le radiolist !

sed -i ‘s/$/ \/’ /tmp/RADIO/NbDir.txt

On prépare la dernière ligne

tail -n 1 /tmp/RADIO/NbDir.txt > /tmp/RADIO/Last.txt

On prépare la syntaxe pour la dernière ligne

sed -i ‘s/ \/ 3>&1 1>&2 2>&3)/’ /tmp/RADIO/Last.txt

On supprime la dernière ligne qui finit par un \

echo “sed ‘${Dnum}d’ /tmp/RADIO/NbDir.txt > /tmp/RADIO/radio.txt” > /tmp/RADIO/sed
bash /tmp/RADIO/sed

On ajoute la dernière ligne avec la syntaxe qui va bien

cat /tmp/RADIO/Last.txt >> /tmp/RADIO/radio.txt

On numérote les lignes

cat -n /tmp/RADIO/radio.txt > /tmp/RADIO/radiolist

On créé un fichier à part sans esapce en début de ligne

sed ‘s/^[ \t]*//’ /tmp/RADIO/radiolist > /tmp/RADIO/radiolistnospace

Ce fichier est enfermé dans une variable

FolderList=$(cat /tmp/RADIO/radiolistnospace)

insertion des variables dans le radiolist dans un fhichier texte

echo “Folder_choice=$(whiptail --menu “Choisissez parmis les dossiers :” --nocancel 20 80 ${Dnum} \
${FolderList}
echo $Folder_choice > /tmp/RADIO/Folder_choice” > /tmp/RADIO/RadioQuest

Exécution du fichier

bash /tmp/RADIO/RadioQuest

On récupère le résultat de la question dans une variable

Folder_choice=$(cat /tmp/RADIO/Folder_choice)

On vérifie que ça marche

echo ${Folder_choice}

On supprime les fichiers temporels

rm -rf /tmp/RADIO

[/code]

Si quelqu’un sait comment utiliser l’option gauge de whiptail sans avoir à installer pv je prends (mon objectif est que le script puisse s’exécuter à partir d’une intall Debian Fraîche et en NetInstall) !!

A+ sous linux

Salut vincentsan,
(Ce pseudo me fera toujours rire, j’avais un prof de japonais qui s’appelait Vincent. Du coup, le “Konichi-wa Vincent-san” est gravé dans ma mémoire ^^)

Je lis encore une fois très rapidement ce post. Désolé, mais je crois que le temps est une ressource devenue bien trop rare dans ma vie. Du coup, plutôit que de poster des remarques par rapport à ton code, je te propose un snippet qui traîne sur stackoverflow pour créer un navigateur de fichier avec whiptail. Testé et éprouvé dans de nombreux cas de figures, et compatible sh (même si tu t’en fous).

[code]# This function provides a browser to choose a file

$1 is the title of the window (mandatory)

$2 is the expected filename

$3 is the directory to start with, / by default

returns the full name of the chosen file

Filebrowser() {
if [ -z $3 ]; then
filepath=$(ls -lhp / | awk -F ’ ’ ’ { print $9 " " $5 } ')
else
filepath=$(ls -lhp “/$3” | awk -F ’ ’ ’ { print $9 " " $5 } ')
fi
if [ -z $3 ]; then
pathselect=$(whiptail --menu “$1”
40 50 30 --cancel-button Cancel --ok-button Select $filepath
3>&1 1>&2 2>&3)
else
pathselect=$(whiptail --menu “$1”
40 50 30 --cancel-button Cancel --ok-button Select …/ BACK $filepath
3>&1 1>&2 2>&3)
fi
RET=$?
if [ $RET -eq 1 ]; then
echo "Cancel"
exit 1
elif [ $RET -eq 0 ]; then
if [ -d “/$3$pathselect” ]; then
Filebrowser “$1” “$2” "/$3$pathselect"
elif [ -f “/$3$pathselect” ]; then
filefullname=readlink -m "$3$pathselect"
filebasename=basename "$filefullname"
if [ “$filebasename” = “$2” ]; then
echo "$filefullname"
exit 0
else
whiptail --msgbox --title "! ERROR ! "
“Selected file does not seem to be the expected file.”
8 44 3>&1 1>&2 2>&3
Filebrowser “$1” "$2"
fi
else
whiptail --msgbox --title “! ERROR !”
“Error setting path to setup file.”
8 44 3>&1 1>&2 2>&3
unset base
unset filepath
Filebrowser “$1” "$2"
fi
exit 0
fi
}[/code]

Pour l’utiliser, c’est simple :

Le code est assez simple à modifier si tu ne veux pas un nom de fichier spécifique. De manière plus générale, utiliser une fonctione récursive dans ton cas me semble être une bonne idée. Inspire-toi de ce code. (Si ça ne s’applique pas à ton cas, désolé… J’écris ce message assez vite.)

Quant à l’utilisation de l’option gauge, je ne sais pas trop pourquoi tu veux utiliser pv. Ceci fonctionne plutôt bien :

( for i in `seq 1 100` do echo $i sleep 1 done echo "EOF" ) | whiptail --gauge "text" 20 20 0
Attention à garder les parenthèses, sinon seul la sortie standard du dernier echo sera redirigée vers l’entrée standard de whiptail. Ce serait équivalent à quelque-chose comme ça :

for i in `seq 1 100` do echo $i sleep 1 done (echo "EOF" | whiptail --gauge "text" 20 20 0)

J’espère que ce message t’aide un peu.

A+
Moi

Salut Dunatatos,

Merci pour ta réponse, en ce qui concerne whiptail, j’ai vu pleins de docs qui renvoient à la même commande que celle citée. Il me semble que l’utilisation de pv est obligatoire pour que la jauge soit rattachée à une commande du genre tar ou apt-get update. C’est à dire que la jauge en % corresponde au temps mis par une commande pour s’effectuer et remplace la sortie standard de la commande tar ou apt-get…
Je suis un peu long à la comprenette… Ce que je comprends de ce genre d’exemple c’est qu’on peut afficher un jauge reliée à rien. A quoi bon ? En utilisant l’option gauge comme ça elle durera forcement 100 secondes même si l’extraction dure 5 minutes… :12

Exemple avec dialog de ce que je souhaiterai faire en me passant de l’install de pv :

[code]apt-get install pv dialog

(pv -n file.tgz | tar xzf - -C target_directory )
2>&1 | dialog --gauge “Extracting file…” 6 50[/code]
source : http://superuser.com/questions/168749/is-there-a-way-to-see-any-tar-progress-per-file

Super ton exemple de navigateur !! :023
Je l’ai un peu modifié pour qu’on ne soit pas obligé d’indiquer un nom de fichier et qu’il rentre dans un écran à résolution moyenne genre 1366 x 768 :

[code]# This function provides a browser to choose a file

$1 is the title of the window (mandatory)

$2 is the expected filename

$3 is the directory to start with, / by default

returns the full name of the chosen file

Filebrowser() {
if [ -z $3 ]; then
filepath=$(ls -lhp / | awk -F ’ ’ ’ { print $9 " " $5 } ')
else
filepath=$(ls -lhp “/$3” | awk -F ’ ’ ’ { print $9 " " $5 } ')
fi
if [ -z $3 ]; then
pathselect=$(whiptail --menu “$1”
20 80 10 --cancel-button Cancel --ok-button Select $filepath
3>&1 1>&2 2>&3)
else
pathselect=$(whiptail --menu “$1”
20 80 10 --cancel-button Cancel --ok-button Select …/ BACK $filepath
3>&1 1>&2 2>&3)
fi
RET=$?
if [ $RET -eq 1 ]; then
echo “Cancel”
exit 1
elif [ $RET -eq 0 ]; then
if [ -d “/$3$pathselect” ]; then
Filebrowser “$1” “$2” “/$3$pathselect”
elif [ -f “/$3$pathselect” ]; then
filefullname=readlink -m "$3$pathselect"
filebasename=basename "$filefullname"
if [ “$filebasename” = “$2” ]; then
echo “$filefullname”
exit 0
else
if [ “$filefullname” = “$(pwd)/initrd.img” ] || [ “$filefullname” = “$(pwd)/vmlinuz” ]; then
whiptail --msgbox “Il est fortement déconseillé de toucher aux fichiers initrd.img ou vmlinuz” 20 80 --nocancel 3>&1 1>&2 2>&3
exit 1
fi
echo “$filefullname”
fi
fi
exit 0
fi
}
Filebrowser “Navigateur de Sélection de Fichier Standards”[/code]

Pour le lancer on tape juste le nom du script :slightly_smiling:
Le seul problème est que ça ne marche pas vraiment pour les fichiers spéciaux (sockets, blocks, fifo…)
Mais en revanche on peut récupérer un nom de fichier + son chemin absolu dans la variable $filefullname :slightly_smiling:

En fait je n’ai pas trouvé sur stack overflow le post d’où tu as tiré le script, du coup j’ai pas vraiment compris le contexte et je l’ai un peu modifié…

J’ai pas vraiment compris non plus pourquoi des fichiers à la racine du système apparaissent comme étant dans le répertoire à partir duquel on se trouve dans le shell. C’est pour cela que j’ai ajouté la boucle :

if [ "$filefullname" = "$(pwd)/initrd.img" ] || [ "$filefullname" = "$(pwd)/vmlinuz" ]; then whiptail --msgbox "Il est fortement déconseillé de toucher aux fichiers initrd.img ou vmlinuz" 20 80 --nocancel 3>&1 1>&2 2>&3 exit 1 fi

J’avais pas trop d’idée pour résoudre le problème…

En ce qui concerne l’utilité du script qui liste un répertoire voir ici :
https://www.debian-fr.org/backup-retaure-samba4-ad-t54293.html

Merci de m’avoir répondu et d’avoir enrichi le post. J’espère qu’on pourra centraliser des astuces sur whiptail car les docs sur le net ne sont pas vraiment exhaustives (ou intelligibles) pour les néophytes du script comme moi.

さようなら (non je ne parle ni n’écris le japonais mais google est mon ami. A moins que non j’ai peut-être copié une insulte ?)

VincentSan (je suis plus viet que jap mais le pseudo me plaît aussi)

En fait, pv ne sert qu’à écrire une progression sur la sortie standard. Si tu trouves un autre moyen d’évaluer la progression, pv n’est pas utile.
Tu peux peut-être te pencher sur les options --checkpoint et --checkpoint-action de tar (par exemple), ou évaluer la taille des fichiers dans le cas d’une copie.
(Voir la dernière reṕonse sur le lien que tu me donnes : superuser.com/a/319207/534361 même si elle manque de détails…)

L’idée de l’exemple, c’est de remplacer la boucle for par autre chose qui écrit une progression sur la sortie standard. Le design pattern que je prendrais comme référence est un truc comme ça :

[code]# This function returns the ratio between the file $1 and $2, in percentage
progress_cp {
progress=0
while [ $progress != 100 ]
do
[…]
[ code à base de calcul de fraction et de ls/du/df en fonction des types de copie à supporter pour calculer $progress ]
echo $progress
sleep 1
done
echo “EOF”
}

cp $file1 $file2 & # l’esperluette permette de lancer le processus en arrière plan
progress_cp $file1 $file2 | whiptail …[/code]

Il manque quelques morceaux, comme s’assurer que la copie est bien finie. Même si la progression est à 100%, la copie peut ne pas être terminée (dans le cas de gros fichiers, par exemple).

Il y a peut-être des erreurs de syntaxe là dedans (je pense surtout à des parenthèses manquantes ou des conditions mal écrites), j’ai écrit ça à l’arrache sans tester.

Hello,

Effectivement j’ai déjà essayé de regarder de ce côté là mais sans aucun succès. Je pense que c’est bien au dessus de mes moyens pour le moment.

Merci quand même d’avoir regardé. :023

A+

VincentSan

Hop hop hop, un extrait épuré de l’un de mes scripts :

[code]dunatotatos@PC-Duna:/tmp/vincentsan$ ls -lArth
total 2.6G
-rw-r–r-- 1 dunatotatos dunatotatos 2.6G Jan 18 11:15 file0
-rwxr-xr-x 1 dunatotatos dunatotatos 286 Jan 18 11:17 cp_progress.sh
dunatotatos@PC-Duna:/tmp/vincentsan$ cat cp_progress.sh
echo_prg() {
prg=0
while [ $prg -ne 100 ]
do
size1=$(stat -c “%s” $1)
size2=$(stat -c “%s” $2)
prg=$(( $size2 * 100 / $size1 ))
echo $prg
done
echo “EOF”
}

cp “$1” “$2” &

(echo_prg “$1” “$2”) | whiptail --gauge “text” 20 20 0

wait
dunatotatos@PC-Duna:/tmp/vincentsan$ ./cp_progress.sh file0 file1
dunatotatos@PC-Duna:/tmp/vincentsan$ [/code]

(file0 est juste un fichier rempli de 0.

Euh, quoi ?? Cette fonction commence par parcourir la racine. Pour commencer par le dossier courant, il faut lui donner un troisième argument :

D’ailleurs, attention dans ta version modifiée. Tu n’utilises plus le deuxième argument (le nom du fichier attendu), alors supprime-le. Le troisième argument devient le deuxième. Une version modifiée plus correcte serait ceci :

[code]# This function provides a browser to choose a file

$1 is the title of the window (mandatory)

$2 is the directory to start with, / by default

returns the full name of the chosen file

Filebrowser() {
if [ -z $2 ]; then
filepath=$(ls -lhp / | awk -F ’ ’ ’ { print $9 " " $5 } ')
else
filepath=$(ls -lhp “/$2” | awk -F ’ ’ ’ { print $9 " " $5 } ')
fi
if [ -z $2 ]; then
pathselect=$(whiptail --menu “$1”
20 80 10 --cancel-button Cancel --ok-button Select $filepath
3>&1 1>&2 2>&3)
else
pathselect=$(whiptail --menu “$1”
20 80 10 --cancel-button Cancel --ok-button Select …/ BACK $filepath
3>&1 1>&2 2>&3)
fi
RET=$?
if [ $RET -eq 1 ]; then
echo "Cancel"
exit 1
elif [ $RET -eq 0 ]; then
if [ -d “/$3$pathselect” ]; then
Filebrowser “$1” "/$2$pathselect"
elif [ -f “/$2$pathselect” ]; then
filefullname=readlink -m "$2$pathselect"
echo $filefullname
exit 0
fi
}
Filebrowser “Navigateur de Sélection de Fichier Standards” “$(pwd)”[/code]

D’ailleurs, ta condition supplémentaire est vraiment bizarre.

Pourquoi ne pas utiliser la variable $filebasename précédemment calculée ? Pourquoi refuser spécifiquement ces deux fichiers et pas autre chose comme le contenu de /boot ?

EDIT : J’ai retrouvé le snippet. Il n’était pas sur stackoverflow, mais sur un autre site web : sirlagz.net/2013/11/08/snippet-w … e-browser/