Создать меню bash на основе списка файлов (сопоставить файлы с числами)

Этот ответ показывает большое и интуитивно понятное меню bash , в котором вы просто нажимаете номер и выбирается пункт. Но это немного неудобно для списка файлов, потому что все это жестко закодировано. Я бы предпочел заполнить свои файлы каким-нибудь массивом, а затем позволить пользователю выбрать число, которое снова отображается на смещение массива.


В основном это то, что я себе представляю:

Following `*.war` archives were found, select one:

  1) old.war
  2) debug.war
  3) release.war

Use number to select a file or 'stop' to cancel: blah
'blah' is not a number
Use number to select a file or 'stop' to cancel: 2
debug.war installed

Но как мне превратить список файлов в этот массив:

options=("Option 1" "Option 2" "Option 3" "Quit")

Как получить строку в определенное смещение в options? Как я могу убедиться, что пользователю предлагается повторить попытку? Можно ли разрешить строке stop остановить режим выбора?

6
задан 13 April 2017 в 15:24

3 ответа

Сохранить выводы find в a bash выстройте используют это:

unset options i
while IFS= read -r -d $'\0' f; do
  options[i++]="$f"
done < <(find /dir/ -maxdepth 1 -type f -name "*.war" -print0 )
  • read читает вход из find пустой указатель разграничен (-d $'\0').
    • Массив $options заполнено именами файлов.
  • find поиски только файлов (-type f) в рамках данного каталога (-maxdepth 1) с окончанием .war (-name "*.war") и печатает их delimted нулевым символом (-print0).

Избранное меню может быть сделано как это:

select opt in "${options[@]}" "Stop the script"; do
  case $opt in
    *.war)
      echo "War file $opt selected"
      # processing
      ;;
    "Stop the script")
      echo "You chose to stop"
      break
      ;;
    *)
      echo "This is not a number"
      ;;
  esac
done

Это работает следующим образом:

1) /dir/old.war
2) /dir/debug.war
3) /dir/release.war
4) Stop the script
#? test
This is not a number
#? 2
War file /dir/debug.war selected
#? 4
You chose to stop
12
ответ дан 14 April 2017 в 01:24
  • 1
    Я думаю так. Динамическое разделение является собственной системой/методом Microsoft, и необходимо использовать различную систему/метод раздела для Linux. Это возможно, но все данные в диске будут потеряны. Таким образом, если это - то, что Вы хотите, необходимо скопировать содержание разделов NTFS ' data' и ' backup' к другому диску. (Или, возможно, получите другой диск для Linux и создайте таблицу разделов и разделы с gparted на этом новом диске). Если это не то, что Вы хотите, можно установить VirtualBox в Windows и установке Ubuntu в виртуальной машине из VirtualBox. – sudodus 25 December 2016 в 21:21

select может сделать большую часть из этого для Вас, без особых усилий необходимый.

, Как я поворачиваю список файлов в эту штуку массива?

Вы не на самом деле должны. select берет серию слов для отображения как опции. Они могут быть даны непосредственно (select color in red green blue) или прибывать из расширения шарика файла (select file in *.war), а также расширение массива в слова как, пример, который Вы нашли, делает (select option in "${options[@]}").

, Как я получаю строку при определенном смещении в опциях?

select делает это автоматически и хранит его в переменную, которую Вы обеспечиваете. (Если вход пользователя недопустим, он хранит пустую строку.)

, Как я удостоверяюсь, пользователя просят попробовать еще раз?

Снова select делает это для Вас, потому что выбор делает цикл , как while. Это будет продолжать спрашивать до Вас break из цикла (или пока это не считает EOF, обычно вводимый Ctrl + D ).

я могу позволить, чтобы строка stop остановила режим выбора?

Да, вход пользователя помещается в переменную REPLY, независимо от того, соответствует ли это одной из опций, таким образом, можно проверить на определенные значения и обработать их по-другому.

Соединение всего этого:

echo "The following `*.war` archives were found; select one:"

# set the prompt used by select, replacing "#?"
PS3="Use number to select a file or 'stop' to cancel: "

# allow the user to choose a file
select filename in *.war
do
    # leave the loop if the user says 'stop'
    if [[ "$REPLY" == stop ]]; then break; fi

    # complain if no file was selected, and loop to ask again
    if [[ "$filename" == "" ]]
    then
        echo "'$REPLY' is not a valid number"
        continue
    fi

    # now we can use the selected file
    echo "$filename installed"

    # it'll ask for another unless we leave the loop
    break
done
4
ответ дан 14 April 2017 в 01:24
  • 1
    Файл wouldn' t быть пробелом. Это все еще имело бы содержание файлов 1 - 5. Если там файлы 1,2,3,5,6,7.. 9, с разрывом в четыре, тогда этот цикл только произведет 1 - 3. – muru 25 December 2016 в 17:44

Вы могли также использовать шарик оболочки для получения списка файлов. Этот подход имеет преимущество не использования внешней программы (find) и не необходимости в любом ограничении на тип файла (*war, например) данный:

#!/usr/bin/env bash

## Collect the files in the array $files
files=( ~/foo/war/* )
## Enable extended globbing. This lets us use @(foo|bar) to
## match either 'foo' or 'bar'.
shopt -s extglob

## Start building the string to match against.
string="@(${files[0]}"
## Add the rest of the files to the string
for((i=1;i<${#files[@]};i++))
do
    string+="|${files[$i]}"
done
## Close the parenthesis. $string is now @(file1|file2|...|fileN)
string+=")"

## Show the menu. This will list all files and the string "quit"
select file in "${files[@]}" "quit"
do
    case $file in
    ## If the choice is one of the files (if it matches $string)
    $string)
        ## Do something here
        echo "$file"
        ## Uncomment this line if you don't want the menu to
        ## be shown again
        # break;
        ;;

    "quit")
        ## Exit
        exit;;
    *)
        file=""
        echo "Please choose a number from 1 to $((${#files[@]}+1))";;
    esac
done
7
ответ дан 14 April 2017 в 01:24
  • 1
    Я не мог отредактировать предыдущий комментарий. Я надеюсь, что это объясняет лучше: Я думаю, что Это невозможно для использования Microsoft Dynamic Disk или Microsoft Dynamic Partition для Linux, и Ubuntu является операционной системой Linux. Но можно выполнить Ubuntu в VirtualBox (в Windows). – sudodus 25 December 2016 в 21:28

Другие вопросы по тегам:

Похожие вопросы: