Заклинание Bash для программного определения радиолиста - PullRequest
1 голос
/ 01 мая 2019

Я хочу выполнить команду bash, подобную этой:

whiptail --title 'Select Database' --radiolist 'Select Database:' 10 80 2 \
  1 production off \
  2 localhost  on

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

Список баз данных доступен в переменных с именем DBS, а ACTIVE_DB - это элемент списка радиоликов, который нужно выделить в диалоге whiptail.

Вот мои текущие усилия по созданию командной строки.Это, вероятно, слишком запутанно.

DBS="production localhost"
ACTIVE_DB="localhost"
DB_COUNT="$( echo "$DBS" | wc -w )"

DB_LIST="$(
  I=1
  echo ""
  for DB in $DBS; do
    SELECTED="$( if [ "$DB" == "$ACTIVE_DB" ]; then echo " on"; else echo " off"; fi )"
    SLASH="$( if (( $I < $DB_COUNT )); then echo \\; fi )"
    echo "  $I $DB $SELECTED $SLASH"
    echo ""
    I=$(( I + 1 ))
  done
)"

OPERATION="whiptail \
  --title \"Select Database\" \
  --radiolist \
  \"Select Database:\" \
  10 80 $DB_COUNT \"${DB_LIST[@]}\""

eval "${OPERATION}"

Я довольно близко.Как вы можете видеть, расширение содержит одинарные кавычки, которые запутывают вещи, а обратные косые черты отсутствуют в некоторых EOL:

set -xv 
++ whiptail --title 'Select Database' --radiolist 'Select Database:' 10 80 2 '
  1 production  off
  2 localhost  on '

В решении необходимо как-то узнать, какой выбор сделал пользователь, или еслиони нажали ESC.ESC обычно устанавливает код возврата на 255, так что это не должно быть трудным, однако эта проблема становится действительно запутанной при попытке получить значение выбранного пользователем радиолистического элемента.

Ответы [ 2 ]

3 голосов
/ 01 мая 2019

Следующие передовые методы изложены в BashFAQ # 50 :

# note that lower-case variable names are reserved for application use by POSIX
# see https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html
active_db="localhost"
dbs=( production localhost ) # using an array, not a string, means ${#dbs[@]} counts

# initialize an array with our explicit arguments
whiptail_args=(
  --title "Select Database"
  --radiolist "Select Database:"
  10 80 "${#dbs[@]}"  # note the use of ${#arrayname[@]} to get count of entries
)

i=0
for db in "${dbs[@]}"; do
  whiptail_args+=( "$((++i))" "$db" )
  if [[ $db = "$active_db" ]]; then    # only RHS needs quoting in [[ ]]
    whiptail_args+=( "on" )
  else
    whiptail_args+=( "off" )
  fi
done

# collect both stdout and exit status
# to grok the file descriptor switch, see https://stackoverflow.com/a/1970254/14122
whiptail_out=$(whiptail "${whiptail_args[@]}" 3>&1 1>&2 2>&3); whiptail_retval=$?

# display what we collected
declare -p whiptail_out whiptail_retval

Хотя у меня нет whiptail удобного для тестирования, точный вызов, выполняемый приведенным выше кодом, точно идентичен:

whiptail --title "Select Database" \
         --radiolist "Select Database:" 10 80 2 \
          1 production off \
          2 localhost on 

... как строка, которая, когда eval ed выполняет точную команду, может быть сгенерирована с помощью:

printf '%q ' whiptail "${whiptail_args[@]}"; echo
1 голос
/ 01 мая 2019

Использовать массивы.Они сделают это в десять раз легче.Давайте начнем с малого и продолжим наш путь.Вот $DBS и $DB_COUNT в виде массива:

DBS=(production localhost)
DB_COUNT=${#DBS[@]}

Преимущество здесь в том, что $DBS на самом деле имеет две записи, поэтому мы можем подсчитать количество записей с помощью ${#DBS[@]} без необходимости оболочкидля внешних команд, таких как wc.

Так что теперь давайте займемся $DB_LIST.Вы пытаетесь добавить пару вариантов каждой итерации цикла.Давайте преобразуем это в синтаксис массива, используя array+=(foo bar baz) для добавления элементов.

DB_LIST=()
I=1
for DB in "${DBS[@]}"; do
  if [ "$DB" == "$ACTIVE_DB" ]; then SELECTED=on; else SELECTED=off; fi
  DB_LIST+=("$I" "$DB" "$SELECTED")
  I=$(( I + 1 ))
done

Обратные слэши и новые строки интерпретируются оболочкой, а не whiptail.Нет необходимости бросать их в массив, поэтому я избавился от всей переменной $SLASH.Новые строки не имеют значения, так что до свидания echo "".

Наконец-то, давайте запустим хлыстовик.Больше нет необходимости в сумасшедших цитатах и ​​eval.Мы можем просто запустить его напрямую и расширить массив, который мы построили в нужном месте.

whiptail --title "Select Database" --radiolist "Select Database:" 10 80 "$DB_COUNT" "${DB_LIST[@]}"

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

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