Это будет наглая реклама. Даже самореклама. Но тем не менее, в отличие от практически всех остальных реклам, я надеюсь, она будет таки полезна окружающим. Или хотя бы части из них.
Речь пойдет о шэле и иксах. Или как скрестить ежа с ужом и получить два метра колючей проволоки.
Немного предыстории. Я тулкитофоб. Не люблю qt. Потому что c++, который я тоже не люблю. Motif и соответственно все tk были идеальны. Пока не заснули в конце 90-х. Xaw — вещь, конечно, хорошая, но тоже убогая еще больше чем motif. Потому и пришлось остановиться на gtk, о чем пока и не жалею.
Теперь к делу. Для начала приведу любимую цитату из TAOUP Реймонда. Можно считать, что это эпиграф:
«В одной строке кода shell-сценария больше духа UNIX, чем в десяти тысячах строк на языке С!»
Есть в составе GNOME такая хорошая программа, как zenity. Позволяет создавать диалоговые окошки на манер dialog. Все хорошо, да только не развивается нифига. Пришлось форкать, т.к. в багтраке у них тишина, патчи чересчур сложные, да и вообще. Форкнул. Вроде получилось симпатично.
code.google.com/p/yad
Несколько примеров, чтобы понять отличия.
Пример нумер раз, редактор списка автоматом запускаемых программ, как это советует freedesktop:
Пример два, состоящий из двух частей. Автомонтирование флешек баз hal-ов, divicekit-ов и прочей ерунды.
Первое, создаем правила для udev:
И второе — следим за ними:
Комментариев не даю к коду сознательно, так как считаю, что те, кому это может быть полезно, способны разобраться в коде сами.
Речь пойдет о шэле и иксах. Или как скрестить ежа с ужом и получить два метра колючей проволоки.
Немного предыстории. Я тулкитофоб. Не люблю qt. Потому что c++, который я тоже не люблю. Motif и соответственно все tk были идеальны. Пока не заснули в конце 90-х. Xaw — вещь, конечно, хорошая, но тоже убогая еще больше чем motif. Потому и пришлось остановиться на gtk, о чем пока и не жалею.
Теперь к делу. Для начала приведу любимую цитату из TAOUP Реймонда. Можно считать, что это эпиграф:
«В одной строке кода shell-сценария больше духа UNIX, чем в десяти тысячах строк на языке С!»
Есть в составе GNOME такая хорошая программа, как zenity. Позволяет создавать диалоговые окошки на манер dialog. Все хорошо, да только не развивается нифига. Пришлось форкать, т.к. в багтраке у них тишина, патчи чересчур сложные, да и вообще. Форкнул. Вроде получилось симпатично.
code.google.com/p/yad
Несколько примеров, чтобы понять отличия.
Пример нумер раз, редактор списка автоматом запускаемых программ, как это советует freedesktop:
#! /bin/bash config_dir=${XDG_CONFIG_HOME:-$HOME/.config} results=$(mktemp --tmpdir autostart.XXXXXXXXXX) for f in $config_dir/autostart/*.desktop; do grep -m 1 -e '^[[:blank:]]*Exec' $f | cut -d = -f 2 grep -m 1 -e '^[[:blank:]]*Name' $f | cut -d = -f 2 grep -m 1 -e '^[[:blank:]]*Comment' $f | cut -d = -f 2 done | yad --width=500 --height=300 --title="Autostart editor" --image="gtk-execute" \ --text="Add/remove autostart items" --list --editable --print-all \ --multiple --column="Command" --column="Name" --column="Description" > $results if [[ $? -eq 0 ]]; then rm -f $config_dir/autostart/*.desktop i=0 cat $results | while read line; do eval $(echo $line | awk -F'|' '{printf "export NAME=\"%s\" COMMENT=\"%s\" COMMAND=\"%s\"", $2, $3, $1}') cat > $config_dir/autostart/$i$NAME.desktop << EOF [Desktop Entry] Encoding=UTF-8 Name=$NAME Comment=$COMMENT Exec=$COMMAND StartupNotify=true Terminal=false EOF $((i++)) done unset NAME COMMENT COMMAND fi rm -f $results exit 0
Пример два, состоящий из двух частей. Автомонтирование флешек баз hal-ов, divicekit-ов и прочей ерунды.
Первое, создаем правила для udev:
KERNEL!="sd[a-z]*", GOTO="auto_mount_end" ACTION=="add", PROGRAM!="/sbin/blkid %N", GOTO="auto_mount_end" # Set environment ACTION=="add", IMPORT{program}="/sbin/blkid -o udev -p -s TYPE -s LABEL %N" # Global mount options ACTION=="add", ENV{mount_options}="noatime,nodiratime,users,umask=0" # Filesystem specific options ACTION=="add", ENV{ID_FS_TYPE}=="vfat", ENV{mount_options}="%E{mount_options},showexec" ACTION=="add", ENV{ID_FS_TYPE}=="ntfs", ENV{mount_options}="%E{mount_options},utf8" # Get mount point # use basename to correctly handle labels such as ../mnt/foo ACTION=="add", ENV{ID_FS_LABEL}=="?*", PROGRAM="/usr/bin/basename '%E{ID_FS_LABEL}'", ENV{dir_name}="%c" ACTION=="add", ENV{dir_name}!="?*", ENV{dir_name}="usbhd-%k" # Main action ACTION=="add", ENV{dir_name}=="?*", RUN+="/bin/mkdir -p '/mnt/usb/%E{dir_name}'", RUN+="/bin/mount -o %E{mount_options} /dev/%k '/mnt/usb/%E{dir_name}'" ACTION=="remove", ENV{dir_name}=="?*", RUN+="/bin/umount -l '/mnt/usb/%E{dir_name}'", RUN+="/bin/rmdir '/mnt/usb/%E{dir_name}'" LABEL="auto_mount_end"
И второе — следим за ними:
#! /bin/sh BASEDIR=/mnt/usb PIPE=$(mktemp -u --tmpdir ${0##*/}.XXXXXXXX) function on_exit () { echo "quit" >&3 rm -f $PIPE } function on_unmount () { gsu umount $1 ret=$? if [[ $ret -eq 0 ]]; then notify-send -u normal -i drive-removable-media -t 900 \ "${1##*/}" "${1##*/} unmounted successfully" else notify-send -u critical -i drive-removable-media -t 1200 \ "${1##*/}" "Unmount ${1##*/} failed (error code $ret)!!!" fi } function update_state () { MENU= for d in $(find $BASEDIR -mindepth 1 -maxdepth 1 -type d); do MENU="${d##*/}!sh -c 'on_unmount $d'|$MENU" done if [[ -z $MENU ]]; then echo "visible:false" >&3 else echo "visible:true" >&3 echo "menu:$MENU" >&3 fi } mkfifo $PIPE exec 3<> $PIPE export -f on_unmount trap on_exit SIGTERM SIGINT yad --notification --listen \ --image=drive-removable-media --text="Removable media" \ --command="xdg-open $BASEDIR" <&3 & update_state inotifywait -m -e create -e delete $BASEDIR 2> /dev/null | while read LINE; do case $(echo $LINE | awk '{print $2}') in "CREATE,ISDIR") update_state ;; "DELETE,ISDIR") update_state ;; esac done
Комментариев не даю к коду сознательно, так как считаю, что те, кому это может быть полезно, способны разобраться в коде сами.