2013-06-03 6 views
0

Я хочу создать простой диалог с bash-dialog. Я работаю с (X) DSL и bash-3.2. Последняя (X) DSL основана на Linux 2.4.31 и поставляется с bash-2.05, однако bash-3.2 загружается из MyDSL/Testing. Итак, мой скрипт работает под «#!/Bin/bash-3.2/bin/bash».пространства bash в пунктах меню whiptail/dialog

Элементы меню, которые пользователи могут выбрать из базы данных.

Пример файла базы данных «якорей»:

Внутреннее освещение | Освещение для использования в помещениях

Наружное освещение | Освещение для наружного применения

Я извлечь данные в массив «опции 'из файла арматуры:

options = ($ (awk -F "|"' { печать $ 1, $ 2}»якорей)

и в терминале 'эхо' массива:

эхо $ {опции [@]}

, который показывает:

«Крытые арматуры» «Освещение для внутреннего использования» «Наружные арматуры» «Освещение для наружного применения»

Это выглядит нормально, чтобы использовать в качестве меню выбора «whiptail», но это не так.Командная строка:

Хлыстохвост --clear --title "Арматура" --menu "Выберите якорь" 50 80 10 $ {опции [@]}

шоу:

column1-cOLUMN2

Indoor-Armatures

Lighting-за

Закрытый использование

Outdoor-Armatures

Lighting-за

наружного применения

в смену:

COLUMN1-COLUMN2

Ind ООКИ якоря-Lighting для внутреннего использования

Открытых якорей-Ligthing для наружного применения

кажется, что элементы массива с двойными кавычками игнорируются или не видели «Хлыстохвост». Я также попробовал «$ {options [@]}», но это всегда приводит к первому слову «Крытый».

Помимо «whiptail», я попробовал «диалог», но они такие же: информация о версии показывает «cdialog (ComeOn Dialog!) Версия 1.1-20080316» в обоих случаях.

У меня очень ограниченные ресурсы и я не хочу рисковать (пока) в «xdialog», «zenity», «dzen» и тому подобное, даже если это решит это. Я также ограничен Linux 2.4.31 из-за XDSL (для XBOX).

Я много просматриваю в Интернете, но безрезультатно. Каким может быть решение с «whiptail/dialog»?

ответ

1

Основная проблема, с которой вы сталкиваетесь, связана с порядком, в котором оболочка анализирует командные строки: она анализирует (и удаляет) кавычки и escape-последовательности, прежде чем заменяет переменные своими значениями, и никогда не возвращается и повторно анализирует любые кавычки или экранирование в пределах замещенных значений. Рассмотрим этот пример:

var='"foo bar"' # Note that the single-quotes will be removed, and the 
        # double-quotes will be treated as part of the variable value. 
somecmd $var # This runs cmd with 2 arguments: '"foo' and 'bar"' 

В вашем случае я не уверен, откуда берутся двойные кавычки; они не находятся в списке файлов, которые вы предоставили, и команда awk не добавит их. Но в любом случае, вы не хотите, чтобы они хранятся как часть стоимости, вы хотите их вокруг переменной ссылки:

var='foo bar' # Again, the single-quotes are removed. 
somecmd "$var" # This runs cmd with a single argument: 'foo bar' 

Ваш случай является немного более сложным, так как вы используете массив, но тот же принцип применяется. Обратите внимание: echo с переменной сильно вводит в заблуждение; если он показывает, что выглядит как правильное цитирование, это на самом деле означает, что что-то ужасно неправильно, потому что оно должно показывать аргументы после удаления цитат.

Итак, как вы его решаете? Попробуйте это:

options=() 
while IFS="|" read col1 col2 || [ -n "$col1" ]; do 
    options+=("$col1" "$col2") # Note the double-quotes around the variable references 
done <armatures 
echo "options:" 
printf " '$s'\n" "${options[@]}" # This prints each array element on a separate line 
whiptail --clear --title "Armatures" --menu "Choose an armature" 50 80 10 "${options[@]}" # Again, double-quotes around the reference 

UPDATE: Я добавил тест ([ -n "$col1" ]), чтобы выполнить петлю для несогласованной последней строки в файле базы данных.

Если двойные кавычки фактически находятся в файле базы данных, вам придется их удалить; самый простой способ справиться с этим, вероятно, раздеться кавычки при добавлении строки в массив, используя способность BASh к так строка замены (замена «"»с пустым) при построении массива:

options=() 
while IFS="|" read col1 col2 || [ -n "$col1" ]; do 
    options+=("${col1//'"'/}" "${col2//'"'/}") 
done <armatures 
+0

Спасибо! Разбор симуляции нелегко понять, но ваше объяснение помогает. Однако существует одна проблема с кодом, который вы предлагаете: последняя запись не отображается в «whiptail», то есть в приведенном выше примере показана только первая запись. Добавив дополнительную запись с помощью только «|», обе записи отображаются в «whiptail». Как я мог избежать добавления дополнительных «|» запись? – linuph

+0

@linuph: Последняя строка в базе данных, вероятно, не завершена (т. Е. Не имеет символа перевода строки в конце); Я добавил тест для запуска цикла для любой непустой строки, даже если она не завершена. BTW, это говорит о том, что файл базы данных не находится в стандартном формате текстового файла unix и может быть в формате DOS вместо этого, и в этом случае в конце каждой строки будет отображаться символ непечатаемого символа каретки (и он будет ветром вверх в конце каждой записи col2). Если это так, есть способы его фильтрации ... –

+0

У меня нет двойных кавычек в базе данных, так что все в порядке. Я проверю завершение последней строки. Еще раз спасибо! – linuph

0

Основная проблема заключается в способ bash (или любой другой оболочки) разбивает командные строки на «слова», как указано в первом ответе. Разделение линии выполняется на основе IFS - внутреннего полевого сепаратора, который установлен в < пробел > <tab> <newline> По умолчанию умные парни (Stephen Bourne и т. д.), которые разработали ранние раковины, явно думали, что это хорошая идея для пользователей, чтобы их можно было изменить. Также приятно, что это может задано многосимвольное значение.

Итак, все, что вам действительно нужно сделать, это установить разделитель полей на новую строку, запустить awk-скрипт, а затем установить его обратно. Вы также должны цитировать массив, когда используете его.

Это должно работать на баш:

IFS=$'\n' 
options=($(awk -F"|" '{ print $1,$2 }' armatures) 
IFS=$' \t\n' 

Члены массива теперь корректно определены. Тогда:

whiptail --clear --title "Armatures" --menu "Choose an armature" 50 80 10 "${options[@]}" 

Для более примитивных оболочек, как Bourne Shell, вам, возможно, потребуется установить ИФС, введя «IFS =» (без кавычек), открывая одиночные кавычки, нажав <Enter>, закрыв с одиночная кавычка. Чтобы сбросить его снова, введите «IFS =» (без кавычек), откройте одинарные кавычки, введите < пробел >, цитируйте (например, Ctrl-V) вкладку <, нажмите < Введите >, затем закройте одну котировку.