Сценарии 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 и если я предполагаю, что это может быть допустимым, то я тест на допустимую длину строки (больше, чем просто количество символов в расширении файла, включая . характер), чтобы быть уверенным.