BASH-скрипты: выбор файла whiptail - PullRequest
6 голосов
/ 14 октября 2009

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

Хлыстохвост

Тем не менее, справочная страница whiptail не так уж полезна и не содержит примеров. После некоторых поисков в 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 yet\n"
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, но я не уверен, как это сделать? Есть указатели? Или вы можете указать мне несколько примеров из кнута?

Ответы [ 5 ]

8 голосов
/ 14 октября 2009

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

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

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

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

Показать меню:

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>        │
                │                                      │
                └──────────────────────────────────────┘
3 голосов
/ 14 октября 2009

Whiptail - это легкая реализация самых популярных функций диалогового окна с использованием библиотеки Newt . Я сделал быструю проверку, и многие функции в Whiptail, похоже, ведут себя как их аналоги в диалоге. Итак, руководство по диалогу должно помочь вам начать. Вы можете найти один здесь , но Google, конечно, ваш друг. С другой стороны, расширенный пример , вероятно, содержит много вдохновения для вашей проблемы.

0 голосов
/ 13 июня 2019

Эта функция является частью моего репозитория функций для wiptail

# ----------------------------------------------------------------------
#  File selection dialog
#
#  Arguments
#     1  Dialog title
#     2  Source path to list files and directories
#     3  File mask (by default *)
#     4  "yes" to allow go back in the file system.
#
#  Returns
#     0  if a file was selected and loads the FILE_SELECTED variable 
#        with the selected file.
#     1  if the user cancels.
# ----------------------------------------------------------------------
function dr_file_select
{
    local TITLE=${1:-$MSG_INFO_TITLE}
    local LOCAL_PATH=${2:-$(pwd)}
    local FILE_MASK=${3:-"*"}
    local ALLOW_BACK=${4:-no}
    local FILES=()

    [ "$ALLOW_BACK" != "no" ] && FILES+=(".." "..")

    # First add folders
    for DIR in $(find $LOCAL_PATH -maxdepth 1 -mindepth 1 -type d -printf "%f " 2> /dev/null)
    do
        FILES+=($DIR "folder")
    done

    # Then add the files
    for FILE in $(find $LOCAL_PATH -maxdepth 1 -type f -name "$FILE_MASK" -printf "%f %s " 2> /dev/null)
    do
        FILES+=($FILE)
    done

    while true
    do
        FILE_SELECTED=$(whiptail --clear --backtitle "$BACK_TITLE" --title "$TITLE" --menu "$LOCAL_PATH" 38 80 30 ${FILES[@]} 3>&1 1>&2 2>&3)

        if [ -z "$FILE_SELECTED" ]; then
            return 1
        else
            if [ "$FILE_SELECTED" = ".." ] && [ "$ALLOW_BACK" != "no" ]; then
                return 0

            elif [ -d "$LOCAL_PATH/$FILE_SELECTED" ] ; then
                if dr_file_select "$TITLE" "$LOCAL_PATH/$FILE_SELECTED" "$FILE_MASK" "yes" ; then
                    if [ "$FILE_SELECTED" != ".." ]; then
                        return 0
                    fi
                else
                    return 1
                fi

            elif [ -f "$LOCAL_PATH/$FILE_SELECTED" ] ; then
                FILE_SELECTED="$LOCAL_PATH/$FILE_SELECTED"
                return 0
            fi
        fi
    done
}

Использование просто

if dr_file_select "Please, select a file" /home/user ; then
        echo "File Selected: \"$FILE_SELECTED\"."
else
        echo "Cancelled!"
fi
0 голосов
/ 26 августа 2017

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

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

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

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

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

0 голосов
/ 14 октября 2009

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...