Сценарии BASH: выбор файла whiptail

Я нашел отличную небольшую программу, которая позволит мне добавлять удобные GUI в мои скрипты Bash;

настоящих

на хлыст man page не все, что полезно и не дает никаких примеров. После некоторых поисков google я понимаю, как создать простое меню да / нет с помощью 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 yetn"
fi

но что я действительно хотел бы создать меню выбора файла с помощью whiptail для замены старого кода, который у меня есть через несколько различные сценарии резервного копирования / восстановления bash у меня есть:

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

Я предполагаю, что это должно быть сделано с помощью опции "--menu " whiptail, но я не уверен, как это сделать? Любой указатели? Или вы можете указать мне на некоторые примеры whiptail?

4 ответов


создайте массив имен файлов и выберите в меню теги:

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 "$(( $s / 64 * 100 + $s % 64 / 8 * 10 + $s % 8 ))")
    files[i+1]="$f"    # save file name
    ((i+=2))
    ((s++))
done

такой метод будет работать, даже если есть имена файлов с пробелами. Если количество файлов велико, вам может потребоваться разработать другую стратегию тегов.

использование Альфа-символов для тегов позволяет нажать букву, чтобы перейти к элементу. Числовые метки, похоже, этого не делают. Если вам не нужно такое поведение, вы можете устранить некоторую сложность.

отобразить меню:

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

если код выхода 255, диалог был отменен.

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

чтобы поймать выбор в переменной, используйте эту структуру (замените команду whiptail на "whiptail-command"):

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

или

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

переменная $result будет содержать букву алфавита, которая соответствует файлу в массиве. К сожалению, Bash до версии 4 не поддерживает ассоциативные массивы. Вы можете рассчитать индекс в массив файла из такой буквы (обратите внимание на "лишнюю" одинарную кавычку):

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

пример:

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>        │
                │                                      │
                └──────────────────────────────────────┘

Whiptail-это легкая реимплементация самых популярных функций продлен вероятно, содержит много вдохновения для вашей проблемы.


Я пробовал следующее, что сработало:

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

вы также можете изменить это на несколько строк, я добавил проверку пустого списка:

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

вам нужно отрегулировать номера для того чтобы получить cleaninterface. И вы можете заменить "-" чем-нибудь еще, если хотите. Но если вы этого не сделаете, вы увидите 2 записи в каждой строке.

кстати: выбранная запись печатается на stderr.

это может нуждаться в некотором улучшении, но для основной идеи, я думаю, этого достаточно.


это, кажется, один из лучших результатов при поиске whiptail, и ни один из предыдущих результатов не работал для меня. Это то, что я использовал:

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

$result будет пустым, если не был сделан допустимый выбор. Я добавил фиктивный выбор в верхней части списка, который возвращает пустую строку в результате, чтобы вы случайно не выбрали неправильный файл, случайно нажав Enter сразу после появления меню. Если вы не хотите этого, тогда в строке "для" удалите +2 в "do j=$((2*$i+2))", а также следующие две строки, которые явно задают a[0] и a[1].

запутанная вещь о whiptail заключается в том, что при чтении из массива в такой ситуации он ожидает два элемента данных на строку, оба из которых отображаются, первый из которых является результатом, который вы хотите вернуть, если ожидается строка (которая в некоторых ситуациях может быть буквой или числом), а второй-любой описательный текст, который вы можете захотеть. Вот почему для первой строки Я использую[0], чтобы дать пустую строку в результате, и[1] в качестве описательного текста, но оттуда первый элемент в паре содержит имя файла (которое я действительно хочу вернуть), а второй-пустая строка, так как я не хочу отображать какой-либо текст, кроме имени файла на этих строках.

также предыдущий пост сказал, что whiptail вернул код ошибки 255, если кнопка отмены была нажата, но это не относится к версии, которую я имею - он возвращает 1. Так что я просто проверить код ошибки 0 и если я предполагаю, что это может быть допустимым, то я тест на допустимую длину строки (больше, чем просто количество символов в расширении файла, включая . характер), чтобы быть уверенным.