Прямая ссылка: https://youtu.be/6HPRNnk_9nU
Tag Archives: it
Список софта из видео «Как выжить на Windows XP в 2020 году»
Официальный сайт
Копия на Mega.NZ
Официальный сайт
Автономный установщик
Firefox Setup 49.0.2
Firefox Setup 52.9.0esr
https://github.com/Feodor2/Mypal/releases
Дистрибутив
Справка (русская)
Копия на Mega.nz (Дистрибутив+справка в RAR SFX-архиве)
KB828041 (первое обновление)
Пакет обеспечения совместимости
Средство удаления скрытых данных
Официальный сайт
Far Manager v3.0 build 5577 x86
Far Manager v2.0 x86
Far Manager v2.0 x86 (урезанная версия для встраивания в образы)
.NET 2.0
.NET 3.5
.NET 4.0
Копии в одном архиве (ZIP)
Aimp + Aimp Tools + Plugins (визуализации) ZIP
Скачать с официального сайта:
Версия x86 (32-разрядная)
Версия x64 (64-разрядная)
Копии:
Версия x86 (32-разрядная)
Версия x64 (64-разрядная)
Выжить на Windows XP в 2020 г. Часть II. Офисные пакеты и антивирусы.
Прямая ссылка: https://youtu.be/ArbPkSVoA7E
Выжить на Windows XP в 2020 г. Часть I
Прямая ссылка: https://youtu.be/Z1Dtpr6EcCA
Linux. Есть ли слово в строке. Есть ли подстрока в строке.
Довольно частой задачей является узнать, встречается ли в строке какое-нибудь слово или же, в более общем случае, подстрока.
Для решения можно воспользоваться внутренними механизмами bash, но я покажу более башенезависимый способ, с помощью grep
. Благо он есть практически везде, даже в каких-нибудь системах, основанных на BusyBox, а вот вместо bash может встретится и просто sh, и что-нибудь более экзотическое.
Предположим, что в переменной STR
имеется строка:
STR="cat lynx lion coguar"
В переменную SUBSTR
запишем первый параметр командной строки скрипта ($1
):
SUBSTR="$1"
Выводим содержимое переменной $STR
, передаем вывод grep
с нужными параметрами, а результат сохраняем в переменную-счетчик:
CNTR=`echo "$STR" | grep -w -c "$SUBSTR"`
В данной команде более всего интересны параметры grep
:
-w
— искать целое слово.
Примечание: Словом по умолчанию считается все, что отделено от других символов пробелом(-ами) табуляцией(-ами) или переводом(-ами) строки.
-с
— подсчитать количество строк с нужным вхождением
Примечание: Ключ -с
заставляет grep
подсчитывать строки, а не сами вхождения, так что количество вхождений слова в строку, так посчитать не получится.
В итоге в переменной CNTR
оказывается 0
, если совпадений нет, и 1
, если совпадение есть, остается только проверить:
if [ "$CNTR" -ne 0 ];then echo "Exist" else echo "Not exist" fi
Примеры работы:
./exist-word lion
Вывод:
Exist
./exist-word dog
./exist-word li
Вывод:
Not exist
Под подстрокой имеется любой набор символов, идущих подряд.
Задача решается аналогично предыдущей, только из параметров grep
удаляется ключ -w
Если из вышеуказанного скрипта удалить ключ -w
grep
‘а, то вывод будет таким:
./exist-word li
Вывод:
Exist
Т.е. теперь была найдена подстрока li
(часть слова lion
).
Linux shell, pipes (конвейеры) и код завершения.
При работе с конвейерами (пайпами, «трубами», pipe), часто возникает вопрос, как отловить ошибку, произошедшую внутри конвейера.
Для примера возьмем код, где ход загрузки файла отображается dialog’овым прогрессбаром (копия):
#!/bin/bash
FADDR="http://tolik-punkoff.com/static/test.mp3"
wget --progress=dot -O "./test.mp3" "$FADDR" 2>&1 |\
stdbuf -o0 awk '/[.] +[0-9][0-9]?[0-9]?%/ { print substr($0,63,3) }' | \
dialog --gauge "Download file from $FADDR" 10 100
Как видите, конвейер (т.е. передача вывода от одной команды другой через |
), тут налицо.
Если после данной команды просто дописать echo $?
, то будет видно, что результат будет 0
.
И когда все в порядке:

И когда все не в порядке (в данном случае, сделан обрыв связи):

На самом деле, это происходит потому, что в переменной $?
оказывается код завершения последней команды в pipe.
В современных версиях bash перед использованием контейнера, необходимо добавить команду:
set -o pipefail
В старых bash и некоторых других оболочках придется извращаться, может как-нибудь вернусь к вопросу (если для какого утюга что писать буду).
После добавления вышеуказанной команды в скрипт делаем тест с обрывом связи:

Или указываем в переменной $FADDR
некорректный адрес:

Теперь echo $?
отображает корректный код завершения.
Скачивание файла и обработка ошибок в wget. Обратите внимание!
Хотел, конечно, назвать как-нибудь типа «гадское поведение wget
» или «уничтожение файлов wget
‘ом», но остановился на этом. Добавлю ссылку в пост о кодах ошибок (копия) на этот пост.
Но на самом деле, это вроде маленькая и многим известная штука, но которой мало кто задумывается. Особенно, если использует wget
в своих скриптах. Отдельно отметить это меня сподвиг тот самый скрипт, с которого я начал сегодняшний разговор о wget
(копия)
Оказывается, wget
создает новый файл перед закачкой. Несмотря на то, появятся там какие-то ошибки или нет, и несмотря на то, какие ошибки это будут, хоть это ошибки сервера (например 404, файл не найден), или ошибки сети (файл не удалось докачать), файл все равно будет создан. Хотя по логике, например, ошибку сервера (пусть 404) можно было бы сначала и проверить. Но wget
этого не делает, если не случилась ошибка с кодом 2
(ошибка параметров командной строки или конфигурационных файлов).
На самом деле, такой подход довольно правильный, ну и правда, какая разница, почему оно не скачалось (или не сохранилось на диск в случае I/O error
). И для анализа ошибок проблем меньше.
Наибольшую проблему это представляет собой тогда, когда пользователь указывает в параметрах wget
ключ -O <путь к файлу>
, тогда wget
придется его полюбому перезаписать.
Так-то у wget
есть «защита от дурака», если файл, например, file
уже существует, то при следующей закачке файл file
(под тем же именем) будет сохранен, как file.1
, и если что, старый файл останется в целости и сохранности. Но в скриптах ключ -O
удобно использовать. Не надо следить за этими номерами файлов, и вообще в скрипте, wget
без ключей, один сплошной геморрой. Так что ключи используют. Но как же правильно это сделать? Да выбирать место сохранения скачанного и проверять коды ошибок wget
!
1. Скачиваем файл во временный:
wget -O "/tmp/test.tmp" "http://example.org/test.dat"
2. Проверяем коды ошибок (здесь самый простой вариант)
if [ "$?" -eq 0 ]; then #Пункт 3 fi
3. Копируем скачанный файл в целевой: cp /tmp/test.tmp /home/pi/test.dat
Естественно, все имена файлов и пути меняем на свои.
1. Скачиваем файл:
wget -O "~.data/test.dat" "http://example.org/test.dat"
2. Проверяем коды ошибок (здесь самый простой вариант). Если ошибка — завершаем работу:
if [ "$?" -ne 0 ]; then rm "~.data/test.dat" echo "Data download error!" exit fi
Посмотреть размер каталога в Linux. В консоли, но интерактивно и наглядно (ncdu).
И наглядно увидеть, где засрано 🙂
Для отображения размеров каталогов (с подкаталогами), есть стнадартная утилита du
, но, если честно, она не очень удобная. Гораздо удобнее ее аналог, написанный с помощью ncurses — ncdu
Пользоваться очень просто. Заходим в каталог, в котором хотим узнать размеры подкаталогов, и просто вызываем утилиту:
ncdu
Наверное, ее единственный минус, что в каталог уровнем выше, чем тот, из которого ее вызвали, она не переходит. Так что если хотите посмотреть размеры каталогов сразу во всей файловой системе, надо вызывать ее из корня (/
). Но причина такому поведению легко может быть найдена — после запуска утилита сканирует все подкаталоги, чтоб потом нам красиво показать. Чем с более верхнего уровня ее вызываешь, тем дольше процесс сканирования.

Сканирование
В подкаталоги входить можно по
ENTER
, возврат назад по стрелке влево, клавише h
или <
(обычно запятая с шифтом) или по нажатию ENTER
на ..
, как в mc
. Краткая справка по ?
(не забывайте нажать SHIFT
), выход по q
.

Отображение каталогов и их размеров
В Slackware устанавливается штатным образом через sbopkg, как в других линуксах не знаю, в Убунте и Дебиане есть в репозиториях.
Linux wget, коды возврата/завершения. Коды ошибок wget.
Раз уж пошел разговор про wget
(копия), решил я заодно дополнить добрым людям скрипт какими-нибудь осмысленными сообщениями об ошибках, а для того нужны коды завершения.
Кто-то, неизвестно почему, утверждал, что в man их нет. Есть. Но пусть уж будут и тут, и мне от склероза, и мало ли кому другому, кто не любит на буржуйском читать.
0
— OK (ошибок нет)
1
— Иная / общая ошибка (generic error code)
2
— Ошибка в параметрах командной строки или файлах конфигурации (.wgetrc
или .netrc
)
3
— Ошибка файлового ввода/вывода (I/O error)
4
— Ошибка сети (например, при обрыве связи)
5
— Ошибка SSL
6
— Ошибка идентификации (неправильное имя пользователя или пароль)
7
— Ошибка протокола
8
— Ошибка сервера (например, нужный файл на сервере не найден, ошибка 404)
За исключением 0
и 1
, коды выхода с меньшими номерами имеют приоритет над кодами с большими номерами, когда встречаются многочисленные типы ошибок.
Linux wget, тайм-аут и повторы. «Виснет» wget при разрыве связи.
Написали тут с вопросом, мол виснет у нас программа, почему никто не знает, кто ее писал уволился давно, поможи. Ну от чего же не помочь. Программа оказалась башевским скриптом, точнее, набором скриптов. Задача небольшая, выгрузить файл с удаленного сервера, переформатировать и положить на другой сервер, где его подхватывает бухгалтерия. Выгрузка делалась банальным wget
.
Оказалось, скрипт вис, если пропадало соединение с сетью.
Выгрузка производилась простой командой:
wget -O "~/buh01/data/kassa01.dat" "https://example.org/mag01/kassa.dat"
Оказывается, у wget
не проставлен тайм-аут ожидания, а по умолчанию, если его не проставить, wget
будет ждать аж 900 секунд (15 минут). Надо, соответственно, его напрямую указать в параметре ключа -T <секунды> (--timeout=<секунды>)
,
Например, можно поставить вменяемые полминуты (30 с.):
wget --timeout=30 -O "~/buh01/data/kassa01.dat" "https://example.org/mag01/kassa.dat"
Т.е. вис-то, собственно wget
, хотя конечно же, не вис, а терпеливо ждал. Но тут и не бухгалтеру, а даже не сильно опытному пользователю ничего не стоит принять такое поведение за то, что wget
виснет при разрыве соединения.
Заодно можно указать wget
‘у количество попыток для скачивания файла: -t <число>
(--tries=<число>
), тем более, что указание параметра -O
(имя выходного файла) сбрасывает этот параметр в 1.
wget --timeout=30 --tries=3 -O "~/buh01/data/kassa01.dat" "https://example.org/mag01/kassa.dat"
Linux dialog —infobox с «мельницей», скрашивающей процесс ожидания.
Сделал гибрид старого скрипта waiter
(копия) с dialog --infobox
. В infobox
‘е отображается псевдографическая «мельница»
https://www.youtube.com/watch?v=o9KempHy5To
Не стал уж совсем дублировать waiter
, так что никаких параметров демо-скрипт не принимает, просто отсчитывает 10 секунд, показывая псевдографическую «крутилку».
Linux. Удалить комментарии из файла.
Заметка от склероза. Способ ниже удаляет закомментированные, а заодно и пустые строки из файла, но не трогает комментарии в строках. Хорошо помогает почистить какой-нибудь конфиг, в котором комментариев больше, чем самих параметров, и хрен че найдешь:
grep -o '^[^#]*' file.txt > cleaned.txt
Вместо file.txt
подставляем исходный файл, вместо cleaned.txt
— выходной.
Там есть и другие варианты решения задачи.
Замена концов строк MAC (CR, 015 OCT, 0xD HEX) на концы строк Linux (LF, 012 OCT, 0xA HEX)
Понадобилось для работы. Современная MacOS такие концы строк не использует, а некоторое ПО, для совместимости со старыми маками (LC II/LC III) их еще использует. И сами маки в качестве терминалов для наблюдения за датчиками погоды еще юзаются. И живые. Я на таких учился в школе.
Это же аптайам > 20 лет, хуясе. Сии компьютеры младше меня на 5 лет всего. А по характеристикам Intel 486DX 286, ну 386 в лучшем случае, а на них есть оконный интерфейс. Правда, консоли нет и коды ошибок уже не найти (а там скудные сообщения об ошибках — messagebox с кодом).
cat "file.txt" |tr '\015' '\012' >"file2.txt"
Linux. Кодирование/декодирование файлов в/из BASE64
Как однажды сказал мой учитель, «линукс может все, а многое еще и из коробки, надо только знать как». Вот в данном случае именно так и оказалось. Понадобилось мне массово перекодировать файлы в/из BASE64.
BASE64 это такой древний формат данных, использующийся для передачи двоичных данных по сети. В век всеобщего юникода и кучи всякого софта это не так видно пользователю, но когда все только начиналось, с передачей данных была большая жопа. Даже на «железном» уровне некоторые машины поддерживали только семибитную кодировку, а уж о софте, не поддерживающем ничего кроме великого и могучего английского языка и говорить не приходится. Т.е. любой символ кроме букв английского алфавита и цифр мог быть либо выкинут к чертям собачьим, либо невозбранно использован как служебный. Соответственно, любой бинарный файл мог каким либо софтом, например, хитровыебанным почтовым сервером, разорван в клочья при передаче из пункта А в пункт Б.
Вот и придумали умные люди, а давайте все, что не влазит в английский алфавит и цифры, будем по хитрому алгоритму заменять, таки да. На английский алфавит и цифры. Так и получился BASE64. Подобная хрень в криптографии называется «транспортная броня».
Так вот, в Linux из коробки (входит в пакет Coreutils, который есть почти везде) есть утилита, способная кодировать/декодировать BASE64. Называется она, внезапно, base64
.
Для опытов возьмем восьмибитного Сиро Исии. Он, когда живой был, много кого брал на опыты.

base64 isia.png >isia.b64
Закодированный Сиро Исии на Pastebin
base64 -d isia.b64 >isia.decoded.png
Тот случай, когда суть получилась короче преамбулы.
Аналог trim() в bash/linux shell
Пишу небольшой скрипт, для которого надо сохранять две выбранные пользователем при предыдущих запусках скрипта опции, а при следующих запусках их восстанавливать.
Решил воспользоваться самым простым методом. Создаем рядом со скриптом 2 файла, и туда сохраняем значения опций:
echo "$OPT1" > ./option1
echo "$OPT2" > ./option2
Некрасиво, но просто.
При запуске скрипта, читаем опции обратно:
OPT1=`cat ./option1`
OPT2=`cat ./option2`
На всякий случай лучше обрезать лишние пробелы или «пустые» символы типа TAB или переводов строки. Во всяком случае, так рекомендуют во всех руководствах по программированию, и обычно, в каждом современном языке, в некотором виде есть функция trim()
, которая обрезает начальные и конечные пробелы.
Оказывается, что в bash можно обрезать не только начальные пробелы, но даже начальные и конечные пустые строки. Причем решается это одной командой.
Возьмем, например, такой тестовый файл: На PasteBin
Если мы просто выведем его на консоль с помощью команды cat "trimtext.txt"
, то получится следующее:
smallwolfie@wolfschanze:~/myfiles/test/trim# ./testtrim Trim() smallwolfie@wolfschanze:~/myfiles/test/trim#
т.е. со всеми пробелами и пустыми строками.
Самая простая реализация trim()
в shell/bash пропустить вывод команды через xargs
без параметров. xargs
, которая требует после себя команды, без указания команды все равно что echo
без параметров. А echo
без параметров все пустое обрезает.
#!/bin/bash
cat "trimtext.txt"|xargs
Вывод:
./testtrim
Trim()
Модифицировал заметку про опасность использования eval в bash
Об опасности использования eval в bash-скриптах.
За ценное дополнение спасибо wasserstrahl@ljr
Linux dialog, прикручиваем симпатичный progressbar к wget.
Какой бы ваш скрипт не был диалоговым, «само дерево жужжать не может», а в скрипте обычно жужжат утилиты, которые о диалоговых окнах представления не имеют. Так вот прикрутим контролируемый прогрессбар (--gauge
) из виджетов dialog
к всем известному wget
.
#!/bin/bash
FADDR="http://tolik-punkoff.com/static/test.mp3"
wget --progress=dot -O "./test.mp3" "$FADDR" 2>&1 |\
stdbuf -o0 awk '/[.] +[0-9][0-9]?[0-9]?%/ { print substr($0,63,3) }' | \
dialog --gauge "Download file from $FADDR" 10 100
1. Если просто запустить wget
без параметра --progress=dot
(параметр -O "./test.mp3"
здесь показывает путь и имя для сохраняемого файла, для теста оно у нас жестко задано), то wget
попытается нарисовать свой плохенький progressbar:

Использование параметра --progress=dot
приводит вывод на экран в такой вид:

Теперь у нас видны проценты, которые выводятся по штуке на строчку через определенный интервал времени по внутреннему алгоритму wget
.
2. wget
почему-то выводит сообщения о своей работе не на stdout
, а на stderr
. Аж морово поветрие какое-то, ибо и некоторые другие утилиты тоже выводят на stderr
. Оправданно на stderr
выводит сообщения только dialog
, тому ще он всю псевдографику выводит на stdout
. Отучаем wget
писать на stderr
вместо stdout
:
2>&1
2
— зарезервированный канал для stderr
1
— для stdout
. Тут мы просто перенаправляем один канал в другой.
3. Меняем буферизацию. На самом деле, буфер консоли (терминала) выводит на экран сообщение, если в буфере консоли накопилось 1024 байта. Или программа завершилась. Иначе нет. С помощью утилиты stdbuf
устанавливаем буфер stdout
(-o
) в ноль (-o0
), тем самым мы добиваемся, чтоб символы сразу поступали на вход awk
. stdbuf
в качестве второго параметра требует программу, которой она будет посылать измененный буфер. В данном случае awk
.
buffering in standard streams
man stdbuf на русском
За разъяснение спасибо другу из Телеграм.
4. Далее вывод wget
‘а передается awk
, которая хитрой регуляркой и оператором substr
вырезает из вывода все, кроме значений процентов.

5. dialog --gauge
может принимать из stdout
числа, и отображать их в виде progressbar’а

Linux. Определить в скрипте, что программа не найдена. И другие зарезервированные коды завершения.
Понадобилось мне перед запуском скрипта определить, имеется ли в пользовательской системе утилита, которая вызывается в скрипте, и если ее таки нет, сказать юзеру, мол, поставьте, вот ссылка на скачивание.
Оказывается в Linux есть стандартные (зарезервированные) коды завершения, а если программа не найдена, то bash автоматически выдает код завершения 127
. Таким образом, задача сводится к тому, чтобы на код 127
правильно отреагировать.
Можете проверить на этом скрипте:
#!/bin/bash $1 EXITCODE=$? if [ $EXITCODE -eq 127 ]; then echo "Command not found!" else echo "Exit code: $EXITCODE" fi
/excode-test ls
excode-test pb01 pb02 test.mp3
Exit code: 0
Команда существует и выполнена успешно.
./excode-test sagfhjsdgfhjgf
./excode-test: line 3: sagfhjsdgfhjgf: command not found
Command not found!
Примечание: Переменная $?
, содержащая код завершения, будет переопределена любой следующей командой, потому можно взять за правило, сохранять значение $?
в отдельную переменную, если где-то потом в скрипте понадобится проверка кода завершения.
1
— разнообразные ошибки, используется как стандартный код ошибки в скриптах или программах
2
— согласно документации к Bash — неверное использование встроенных команд, иногда программисты его перелпределяют.
126
— вызываемая команда не может быть выполнена, возникает из-за проблем с правами доступа или когда вызван на исполнение неисполняемый файл
127
— «команда не найдена»
128
— неверный аргумент команды exit
128+n
— фатальная ошибка по сигналу «n»
130
— завершение по Control-C
255
— код завершения вне допустимого диапазона, но утилита dialog использует этот код, как завершение по ESC.
Linux dialog —menu. Динамическое меню и прочие штуки
dialog
был бы совсем негибким инструментом, если бы не было возможности формировать элементы меню более-менее «налету», а не только непосредственно в коде скрипта. И такая возможность есть. Виджет --menu
(а также --checklist
и --radiolist
, которые я здесь упущу), принимают на вход массив. Формат массива такой:
MNUARR[0]="Элемент 1"
MNUARR[1]="Описание 1"
MNUARR[2]="Элемент 2"
MNUARR[3]="Описание 2"
...
т.е. линейный массив, где в первый элемент записывается, извиняюсь за тавтологию, элемент, а в следующий — описание, далее все повторяется.
Массив будем брать из файла.
1. Определяем переменную с путем к файлу и массив:
MNUFILE="./dynmenu01.txt"
declare -a MNUARR
2. Заполняем массив:
IDX=0 while read LINE; do PT_1=`echo "$LINE"|awk '{print $1}'` PT_2=`echo "$LINE"|awk '{print $2}'` MNUARR[$IDX]=$PT_1 let "IDX=IDX+1" MNUARR[$IDX]=$PT_2 let "IDX=IDX+1" done <"$MNUFILE"
3. Вызываем dialog
:
dialog --clear \ --title "Dynamic menu" \ --menu "Select option:" \ 20 76 10 \ "${MNUARR[@]}"

Массивом, на самом деле, пользоваться неудобно, и код получается более громоздкий, и несовместимо это может оказаться с другими shell’ами, и возможностей у массива меньше. Есть другой выход — воспользоваться файлом специального формата. Для виджета --menu
формат таков:
"Элемент 1"[пробел]"Описание 1"[пробел]\
"Элемент 2"[пробел]"Описание 2"[пробел]\
Собственно, от описания меню в коде ничем не отличающийся. Можно даже в одну строчку через пробелы все написать, но с пробелом и \ в конце строки симпатичнее.
Остается в параметре --file
виджета --menu
указать путь к файлу.
MNUFILE="./dynmenu-file.txt" dialog --clear \ --title "Dynamic menu" \ --menu "Select option:" \ 20 76 10 \ --file "$MNUFILE" \

С помошью общего для dialog
ключа --item-help
можно добавить к элементам подсказку, появляющуюся в выделенной строке внизу экрана. Подсказка ограничена количеством символов в строке, что не влезло — уползает за экран.
Формат файла для такого меню будет:
"Элемент 1"[пробел]"Описание 1"[пробел]"Помощь 1"[пробел]\
"Элемент 2"[пробел]"Описание 2"[пробел]"Помощь 1"[пробел]\
Точно также меню с помощью описывается и непосредственно в коде скрипта.
Вызов dialog
:
MNUFILE="./dynmenu-file-help.txt" dialog --clear \ --item-help \ --title "Dynamic menu" \ --menu "Select option:" \ 20 76 10 \ --file "$MNUFILE" \
Для динамического меню из массива это не работает (или я не понял как).

Конечно, виджет --menu
, это вам не DataGridView из .NET Framework, и вообще, отдельного виджета для отображения табличных данных у dialog
нет, но, если данных немного, то можно воспользоваться общим параметром для виджетов dialog
‘а
--column-separator
. Раз параметр общий, то кроме --menu
, должен срабатывать и для --checklist
и --radiolist
.
После параметра --column-separator
задаем, собственно, сам разделитель (в примере |
).
Примечание: параметр работает только для описаний пунктов меню.
MNUFILE="./dynmenu-file-sep.txt" dialog --clear \ --item-help \ --column-separator "|" \ --title "Dynamic menu" \ --menu "Select option:" \ 20 76 10 \ --file "$MNUFILE" \

Эта опция работает и для динамического меню, созданного с помощью массива:
Linux dialog —menu, пункт по умолчанию и сохранение выбранного элемента
dialog
— консольная утилита, позволяющая встраивать в ваши скрипты псевдографический интерфейс. Есть и ее графические варианты Kdialog, Xdialog, позволяющие обеспечить ваши скрипты даже полноценным оконным интерфейсом в средах X-сервера.
Как пример можно привести скрипт пакетного переименования файлов (см. на GitHub) работающий в графической среде, или пакетный менеджер Slackware pkgtool
.

pkgtool вид спереди
Утилита древняя, как копролиты динозавра, но почему-то при этом на русском довольно мало примеров в сети и нет хорошей документации, и даже официальные примеры кода не полные, да еще и удалены в некоторых пакетах и их приходится искать отдельно. Слава Ктулху, примеры свободные, потому не грех и перезалить.
Общий синтаксис утилиты dialog
таков:
dialog <общие_параметры> <виджет> <параметры_виджета>
Указание пункта меню по умолчанию возможен не только в виджете --menu
, но и в других виджетах, потому прописать его надо в параметрах, указанных до вызова конкретного виджета.
Если будет указан несуществующий пункт меню или пустая строка, к ошибке это не приведет. Будет выбран первый пункт меню.
dialog --clear --title "Default Item Test" \ --default-item "Item #2" \ --menu "Select item:" \ 20 51 7 \ "Item #1" "Test Item #1" \ "Item #2" "Test Item #2" \ "Item #3" "Test Item #3" 2>"/tmp/dlgres.tmp"

Минус утилиты dialog
в том, что это не связанная система меню, а все-таки отдельная утилита, и, соответственно, один вызов с другим никак не связан. Так что если в скрипте несколько меню и предусматривается возврат в основное, или блуджание по системе меню, то у пользователя может возникнуть неудобство, поскольку при возвратах автоматически будет выбран первый пункт.
Но с помощью опции --default-item
можно сделать так, чтоб при возврате в одно из меню выбирался последний выбранный пункт.
1. Заводим переменную для временного файла:
TEMPFILE="/tmp/dlgres.tmp"
2. И переменную для хранения пути к самой утилите dialog
:
DIALOG="dialog"
Это не обязательно, но удобно, если понадобится переделать скрипт под Xdialog
или Kdialog
3. Заводим переменную для последнего выбранного пункта:
LAST_MENU1=""
4. Само меню будем вызывать из функции menu_in_variable()
Далее внутри функции:
5. Заводим константы для кодов возврата программы dialog
:
OK_C=0 #Нажата кнопка OK в диалоговом окне
ESC_C=255 #Нажата клавиша ESC
CANCEL_C=1 #Нажата кнопка Cancel в диалоговом окне
Примечание: На самом деле с отслеживанием клавиши ESC у утилиты menu
какой-то конфликт с PuTTY, почему-то утилита завершает работу с кодом 255
не только по нажатию ESC, но и по нажатию клавиш F1..F4 Не в PuTTY это не проявляется.
5. Вызываем dialog
:
$DIALOG --clear --title "Save last selected item into variable" \ --default-item "$LAST_MENU1" \ --menu "Select:" 20 60 7 \ "Item #1" "Item 1" \ "Item #2" "Item 2" \ "Item #3" "Item 3" 2>"$TEMPFILE"
Примечание: dialog
записывает в stderr
выбранный элемент меню (в случае виджета --menu
), потому перенаправляем вывод на stderr
во временный файл, путь к которому указан в переменной $TEMPFILE
(2>"$TEMPFILE"
)
6. Сохраняем код возврата:
RETVAL=$?
7. И далее его анализируем. Если нажата кнопка OK, то читаем файл с выбранным пунктом меню в переменную. Если нажата Cancel или клавиша ESC, то на stderr
утилита ничего не выведет и временный файл будет пуст.
case "$RETVAL" in $OK_C) LAST_MENU1=`cat "$TEMPFILE" ` #... ;; $ESC_C) return;; $CANCEL_C) return;; esac
Далее в примере скрипт вернется в главное меню, и если зайти в предыдущее меню еще раз, то пунктом по умолчанию будет последний выбранный пункт.
Иногда удобно сохранять выбранный пункт меню в файл, чтоб при повторном запуске скрипта было видно, какая опция выбрана, если установка опции делается через меню.
Принципиально все делается, как и в предыдущем случае, только заводим еще одну переменную для файла, в котором будем сохранять значение (в реальном скрипте, конечно, можно записывать значение в общий файл конфигурации скрипта):
STATEFILE="./savestate"
И перед вызовом dialog
читаем файл в переменную:
if [ -e "$STATEFILE" ]; then LAST_MENU2=`cat "$STATEFILE"` fi
Далее вызываем dialog
, анализируем код возврата, и если что-то выбрано, копируем временный файл в файл для сохранения:
$DIALOG --clear --title "Save last selected item into file" \ --default-item "$LAST_MENU2" \ --menu "Select:" 20 60 7 \ "Item #1" "Item 1" \ "Item #2" "Item 2" \ "Item #3" "Item 3" 2>"$TEMPFILE" RETVAL=$? case "$RETVAL" in $OK_C) cp "$TEMPFILE" "$STATEFILE" LAST_MENU2=`cat "$STATEFILE"` ;; $ESC_C) return;; $CANCEL_C) return;; esac