簡體   English   中英

BASH 腳本:whiptail 文件選擇

[英]BASH scripts : whiptail file select

我找到了一個很棒的小程序,它可以讓我將用戶友好的 GUI 添加到我的 Bash 腳本中;

鞭尾

然而, whiptail 手冊頁並不是那么有用,也沒有提供任何示例。 做了一些谷歌搜索后,我明白如何使用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}"

我認為這必須通過whiptail的'--menu'選項來完成,但我不確定如何去做? 任何指針? 或者你能指出一些鞭尾例子的方向嗎?

構建文件名數組和菜單選擇標簽:

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將包含對應於數組中文件的字母表中的一個字母。 不幸的是,版本 4 之前的 Bash 不支持關聯數組。 您可以像這樣從字母計算文件數組中的索引(注意“額外”單引號):

((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 是最流行的對話框功能的輕量級重新實現,使用Newt 庫 我做了一個快速檢查,Whiptail 中的許多功能似乎在對話中表現得像它們的對應物。 因此,對話教程應該可以幫助您入門。 你可以在這里找到一個但谷歌當然是你的朋友。 另一方面, 擴展示例可能對您的問題有很多啟發。

這個函數是我的whiptail函數庫的一部分

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

我試過以下方法,效果很好:

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

這可能需要更多的改進,但對於一個基本的想法,我認為這已經足夠了。

當您搜索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 鍵而意外選擇了錯誤的文件。 如果您不想要那樣,則在“for”行中刪除“do j=$((2*$i+2))”中的 +2 以及以下兩行設置 a[0] 和 a [1] 明確。

關於whiptail的令人困惑的事情是,在這種情況下從數組中讀取時,它期望每行有兩個數據項,這兩個都被顯示,第一個是您想要返回的結果,如果該行是預期的(在某些情況下可能是一個字母或數字),第二個是您可能想要的任何描述性文本。 這就是為什么對於第一行,我使用 a[0] 作為結果給出一個空字符串,並使用 a[1] 作為描述性文本,但從那里開始,該對中的第一項包含文件名(這實際上是我的想要返回),第二個是空字符串,因為我不想在這些行上顯示除文件名以外的任何文本。

前一篇文章還說,如果按下取消按鈕,whiptail 會返回錯誤代碼 255,但我的版本並非如此——它返回 1。所以我只測試錯誤代碼 0,如果是我假設它可能是一個有效的條目,然后我測試一個有效的字符串長度(不僅僅是文件擴展名中的字符數,包括 . 字符)以確保。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM