Шаблон Bash для использования zenity (или yad) для вставки / редактирования / удаления записей в файле или базе данных
Я ищу шаблон bash, который использует zenity или yad для ведения списка записей. Шаблон может быть контрольным списком покупок с опцией печати или списком серверов для контроля времени пинга. В любом случае я хотел бы взять этот код и принять его для своих нужд.
Вот пример макета диалогового окна:
Диалоговое окно позволяет выбрать запись и нажать следующие кнопки:
Insert before
(вставить перед выбранной записью). Новая форма ввода монтируется для ввода полей.Edit
(редактировать выбранную запись). Монтирует ту же форму, что и "Вставить перед", за исключением того, что отображаются существующие значения.Delete
(удалить выбранную запись). Содержимое существующей записи отображается и запрашивается подтверждение.Run
- запускает длительный процесс обновления, который обновляет столбец состояния с помощью "MatcheOK / Different / Error". Пользователю предлагается запустить обновление для выбранной записи или всех записей. Индикатор хода выполнения отображается при обработке всех записей.Cancel ALL
- НЕ сохраняйте изменения и не выходите из bash-скрипта. Нажатие Escape или закрытие окна, нажавX
выполняет то же действие. Если какие-либо записи были изменены, запрашивается подтверждение.Save
- сохранить изменения на диске и выйти из скрипта bash.
ПРИМЕЧАНИЕ. Похоже, что zenity позволяет переименовать только кнопки "ОК" и "Отмена". Новые кнопки не могут быть определены в zenity. Таким образом, yad (Y et A nother D ialog), который установлен по умолчанию в Ubuntu и основан на zenity, - это путь. Однако zenity остается в вопросе, потому что основанный на нем скрипт может быть легко преобразован в yad.
Я погуглил существующие примеры, и они самые близкие, но все еще далеки от удовлетворительных:
Используйте zenity из файла скрипта для вставки / просмотра данных в SQL
Пример прокручиваемого поля, слишком длинного, чтобы поместиться в окне
Использование yad (еще одного диалога) форка Zenity для нескольких кнопок
Яд из Source Forge: выключение / перезагрузка / приостановка / выход из системы
ПРИМЕЧАНИЕ: я не ищу полное решение, но что-то близкое, которое можно адаптировать к этому проекту. Хотя этот проект использует простой текстовый файл, существующий сценарий, использующий SQL, ISAM или RDMS, может быть адаптирован. Единственный императив - это писать на bash, а не на python, perl или C и т. Д.
Кто-нибудь может указать на существующий bash-скрипт, который использует zenity (или yad) для вставки / редактирования / удаления записей?
1 ответ
YAD (еще один диалог) - лучший метод
YAD является форком Zenity и предоставляет расширенные возможности управления кнопками, списками и интерфейсами GTK. Например, при вводе имени файла в этом ответе YAD легко предоставляет нам обычный системный интерфейс GUI:
Пример главного диалогового окна
Главное окно скрывает столбец номера записи, который вы можете открыть для целей отладки:
Пример окна вставки / редактирования
Это же окно используется для вставки записей перед существующей записью или редактирования существующей записи:
Обратите внимание на поле "Имя файла". Когда вы вводите его, появляется диалоговое окно выбора файла в первом разделе.
Код Bash
Вот код bash для создания образца шаблона вставки / редактирования / удаления YAD. Обратите внимание, что для чтения в файле по-прежнему необходимо дополнительное кодирование и добавление логики обработки для команды "Выполнить". Дополнительное кодирование, вероятно, требуется для поддержки имен файлов со встроенными пробелами, но это еще не было проверено.
#!/bin/bash
# NAME: websync
# PATH: $HOME/bin
# DESC: Provide list of files and corresponding website addresses.
# DATE: Mar 25, 2017.
# NOTE: Uses yad which is fork of zenity which is GUI fork of dialog.
# TODO: Add local file date modified. Add Answer last revision date.
# Add question title.
# Add file word count, or size, or ignore as irrelevant?
# Add answer word count if file word count is displayed.
# Add answer up votes.
# Scan directory to add all files. ("Populate" button)
# Initialize $ListArr[@] < /home/$USER/bin/.websync
# Use "|" as ListArr delimeter or (double quotes?) for file names with spaces
# Must have the yad package.
command -v yad >/dev/null 2>&1 || { echo >&2 "yad package required but it is not installed. Aborting."; exit 99; }
# Must have the zenity package.
command -v zenity >/dev/null 2>&1 || { echo >&2 "yad package required but it is not installed. Aborting."; exit 99; }
RenumberListArr () {
# This is called after inserting or deleting records.
# Record numbers may not be sequential because user can sort on any column
# Record nubmers must be unique as they are used to find the correct record in ListArr array.
# Matching on "file name" or any other field is impossible because there may be duplicate names.
# Define variables for easy reading and fewer code line changes when expanding
RecArrCnt=5
ListArrCnt=${#ListArr[@]}
i=1 # First element (0) is "false", followed by record number element (1)
j=1 # Record numbers start at 1
while [ $i -lt $ListArrCnt ] ; do
ListArr[$i]=$j
j=$(($j + 1))
i=$(($i + $RecArrCnt))
# echo "Renumber i: $i j: $j"
done
}
OLDIFS="$IFS"
IFS="|"
ListArr=()
# TODO: Replace this section with IFS=' ' read -ra CfgArr < /home/$USER/bin/.websync
ListArr=("${ListArr[@]}" false "1" "/usr/local/bin/display-auto-brightness" "Different")
Modified=$(stat "/usr/local/bin/display-auto-brightness" | grep "Modify:"| cut -f2 -d" ")
echo "Modified: $Modified" # File modified date is a future list array new field
ListArr=("${ListArr[@]}" "http://Ask-ubuntu.ru/questions/894460/automatically-adjust-display-brightness-based-on-sunrise-and-sunset/894470#894470")
ListArr=("${ListArr[@]}" false "2" "/usr/local/bin/sun-hours" "Matches")
ListArr=("${ListArr[@]}" "http://Ask-ubuntu.ru/questions/894460/automatically-adjust-display-brightness-based-on-sunrise-and-sunset/894470#894470")
ListArr=("${ListArr[@]}" false "3" "/etc/cron.daily/sun-hours" "Matches")
ListArr=("${ListArr[@]}" "http://Ask-ubuntu.ru/questions/894460/automatically-adjust-display-brightness-based-on-sunrise-and-sunset/894470#894470")
ListArr=("${ListArr[@]}" false "4" "/home/rick/.conkyrc" "Matches")
ListArr=("${ListArr[@]}" "http://Ask-ubuntu.ru/questions/894460/automatically-adjust-display-brightness-based-on-sunrise-and-sunset/894470#894470")
ListArr=("${ListArr[@]}" false "5" "/usr/local/bin/auto-brightness-config" "Matches")
ListArr=("${ListArr[@]}" "http://Ask-ubuntu.ru/questions/894460/automatically-adjust-display-brightness-based-on-sunrise-and-sunset/894470#894470")
ListArr=("${ListArr[@]}" false "6" "/etc/cron.d/display-auto-brightness" "Matches")
ListArr=("${ListArr[@]}" "http://Ask-ubuntu.ru/questions/894460/automatically-adjust-display-brightness-based-on-sunrise-and-sunset/894470#894470")
ListArr=("${ListArr[@]}" false "7" "/home/rick/bin/indicator-sysmonitor-display" "Different")
ListArr=("${ListArr[@]}" "http://Ask-ubuntu.ru/questions/882419/can-bash-display-in-systray-as-application-indicator/882420#882420")
TransCount=0 # Number of Inserts, Edits and Deletes
# Read Only Status column: Recalc, Different, Matches, Bad File, No Address, Bad Address
# Debugging: --hide-column=2 hides Read Only record number column for normal operation
while true ; do
# adjust width & height below for your screen 900x600 default for 1920x1080 HD screen
# also adjust font="14" below if blue title text is too small or too large
Record=(`yad \
--title "websync - Compare local scripts to those published on internet." --list \
--text '<span foreground="blue" font="14"> \
Click column heading to sort.\
Select record before clicking: Insert / Edit / Delete</span>' \
--width=1200 --height=600 --center --radiolist -separator="$IFS" \
--button="Insert before":10 --button="Edit":20 --button="Delete":30 --button="Run":40 \
--button="Cancel ALL":50 --button="Save":60 --search-column=3 \
--column "Select" --column "Record number" --hide-column=2 --column "File Name" \
--column "Status" --column " Website Address" \
"${ListArr[@]}"`)
Action=$?
RecSelected=false
RecArr=()
i=0
# Button values 1 and 3 don't work for returning selected record for some reason???
# Button values 11, 13 and 15 don't work either. 12, 14 and 16 work.
# Therefore use Button values (10, 20, 30...) for readability.
for Field in "${Record[@]}" ; do
RecSelected=true
RecArr[i++]=$Field
done
# Define variables for easy reading and fewer code line changes when expanding
RecArrCnt=5
ListArrCnt=${#ListArr[@]}
# Error checking
if [[ $Action == 10 ]] || [[ $Action == 20 ]] || [[ $Action == 30 ]] ; then
if [[ $RecSelected == false ]] ; then
zenity --error --text 'You must select a record before clicking: Insert / Edit / Delete.'
continue
fi
fi
# Insert before || or Edit ?
if [[ $Action == 10 ]] || [[ $Action == 20 ]] ; then
RecArr[3]="Recalc"
# --text="Set fields and click OK to update"
# Note if there is a space at end of line, next line generates invalid command error from yad
NewRecArr=(`yad --width=900 --height=300 --title="Link file to Website Address" \
--form --center \
--field="File name":FL --field="Status":RO \
--field="Website Address":TXT \
${RecArr[2]} ${RecArr[3]} ${RecArr[4]}`)
ret=$?
# Cancel =252, OK = 0
# OK & Insert operation?
if [[ $ret == 0 ]] && [[ $Action == 10 ]]; then
# Create new list entry and renumber
((TransCount++)) # Update number of changes
let i=1 # Base 0 array, record number is second field
while [ $i -lt $ListArrCnt ] ; do
if [ ${ListArr[$i]} -eq ${RecArr[1]} ]; then
# We have matching record number to insert before
NewArr+=( false )
NewArr+=( "${ListArr[$i]}" )
NewArr+=( "${NewRecArr[0]}" )
NewArr+=( "${NewRecArr[1]}" )
NewArr+=( "${NewRecArr[2]}" )
fi
let j=$(( $i-1 ))
let k=$(( $j+$RecArrCnt ))
while [ $j -lt $k ] ; do
NewArr+=( "${ListArr[$j]}" )
j=$(($j + 1))
done
let i=$(($i + $RecArrCnt)) # Next list array entry to copy
done
ListArr=("${NewArr[@]}")
unset NewArr
RenumberListArr
# OK & Edit operation?
elif [[ $ret == 0 ]] && [[ $Action == 20 ]]; then
# Update array entry
((TransCount++))
let i=1
while [ $i -lt $ListArrCnt ] ; do
if [ ${ListArr[$i]} -eq ${RecArr[1]} ]; then
# We have matching record number
ListArr[++i]="${NewRecArr[0]}"
ListArr[++i]="New"
ListArr[++i]="${NewRecArr[2]}"
let i=$(($ListArrCnt + 1)) # force exit from while loop
else
let i=$(($i + $RecArrCnt)) # Check next entry
fi
done
fi
# Delete record?
elif [[ $Action == 30 ]] ; then
# --text="click OK to confirm delete"
# Note if there is a space at end of a script line, the next line generates
# "invalid command error from yad
yad --width=900 --height=300 --title="Do you really want to delete this record?" \
--text '<span foreground="blue" font="14">Click OK to confirm delete.</span>' \
--form --center \
--field="File name":RO --field="Status":RO \
--field="Website Address":RO \
${RecArr[2]} ${RecArr[3]} ${RecArr[4]}
ret=$?
# Cancel =252, OK = 0
if [[ $ret == 0 ]] ; then
# Delete record from list array and renumber
((TransCount++))
let i=1
while [ $i -lt $ListArrCnt ] ; do
if [ ${ListArr[$i]} -eq ${RecArr[1]} ]; then
# We have matching record number
j=$(($i - 1))
k=$(($j + $RecArrCnt))
while [ $j -lt $k ] ; do
unset 'ListArr[$j]'
j=$(($j + 1))
done
for i in "${!ListArr[@]}"; do
NewArr+=( "${ListArr[$i]}" )
done
ListArr=("${NewArr[@]}")
unset NewArr
let i=$(($ListArrCnt + 1)) # force exit from while loop
else
let i=$(($i + $RecArrCnt)) # Check next entry
fi
done
RenumberListArr
else
continue # cancel changes.
fi
# Run update process?
elif [[ $Action == 40 ]] ; then
continue # TODO: Run
# Cancel all changes?
elif [[ $Action == 50 ]] || [[ $Action == 252 ]] ; then
# Cancel ALL || or X the window or Escape
if [[ $TransCount -gt 0 ]] ; then
zenity --question --text "You have made $TransCount change(s). Do you really want to cancel?"
rc=$?
if [[ $rc -eq 0 ]] ; then
exit
fi
else
exit
fi
# Save changes?
elif [[ $Action == 60 ]] ; then
# Save
echo ${ListArr[@]} > ~/bin/.websync
exit
else
zenity --error --text "~/bin/websync - Unknown button return code: $Action"
exit
fi
done # End of while loop
IFS="$OLDIFS"
exit
Резюме
Надеемся, что это экономит много времени, заставляя их собственную систему управления записями использовать bash
а также yad
, Конечно, более пуленепробиваемые и, возможно, более быстрые методы могут быть сделаны с использованием Python или C, но это, вероятно, происходит за счет большего количества строк кода и более высокой кривой обучения.
В конце концов, этот проект нацелен на тех, кто хочет больше узнать о bash и о том, что можно сделать в среде bash-only.
Возможно, AskUbuntu - неправильный форум для публикации этого сообщения, и форумы Stack Overflow или Unix & Linux могут быть более подходящими кандидатами для Stack Exchange. Я с нетерпением жду комментариев по этому поводу, поскольку я действительно не уверен, что лучшее место.
Конечно, я всегда с нетерпением жду общих комментариев и конструктивной критики, а также:)