Ну, я снова нахожусь на кривой обучения ... (поздние ночи и много кофе).
Конечным результатом является умеренно используемый bash-скрипт (с использованием sqlite db / table), который делает то, что я был после ... ... т.е. Создает группировку заметок, основанных на названиях окон ...
Это работает .. но это определенно «альфа» ..
Итак, у меня есть мое домашнее приложение ! ... Я размещаю его здесь для всех, кто интересуется «смотри-смотри» ...
Вот он:
#!/bin/bash
clearAllDataAndStartAgain="false"
# Name: tinotes (Title Notes)
#
# What does it do? ... Aside from giving me a great opportunity to learn
# more about bash (and sqlite, which I had previously barely touched).. not much ;)
# Actually, it allows you to keep notes, grouped by window title.
# The notes are kept in an sqlite database.
# Each timestamped note-"event" is stored in a row of the main (only) table.
# You can consolidate notes in a semi ad-hoc manner...
# Notes are presented to you in a single editable text file (in Leafpad).
# You must keep at least one "tinotes" timestamp-line at the top of the text...
# All lines above this topmost timestamp-line are ignored,
# including the "title", which is presented upon each viewing.
# If you remove any/all other "timestamp line(s)", those particular rows are
# deleted from the sqlite table, and the text which remains is associated with
# the immediately preceding timestamp-line (and updated as such in the sqlite table)
#
# How do you drive it? .. Just associate `tinotes.sh` with a shortcut-key.. That's' it!
# Just press the shortcut-key and you will be presented with Leafpad displaying
# a "title line" at the very top, and on line 2, is a "tinotes timestamp" line.
# Type your note below the timestamp-line, then Save and Exit Leafpad,..
# NB.. You MUST fully EXIT Leafpad.. the script cannot proceed until you EXIT Leafpad..
# Leafpad is effectively being used as a Dialog-box with "normal" editing capability.
# A warning Dialog appears if another instance of this script is currently running..
# (actually, if another ***tinotes** leafpad window is running).
#
# Caveat: This version is very much "demo-only"...
# It works, but has typical "alpha" bugs...
# I've presented it here, for anyone who is interested in the general idea.
#
# dependencies
# ============
# sqlite3 ,, the notes are stored in a sqlite db.
# leafpad .. to edit/view the notes (no need to re-invent the wheel)
# wmctrl .. to detect if a ***tinotes*** leafpad window is currently open.
# xdotool .. to get the active window's' ID
# xwininfo .. to get a window's title via it's ID.
# md5sum .. to check for mods to the presented/added notes data
# zenity .. for warning dialog(s)
# sed .. versatile!
# wc .. word count? .. line count (here)
############################################################################
function FinalizeNote {
title="$1"; note="$2"; timeline="$3"; preList="$4"
# Remove trailing whitespace
note="${note%"${note##*[![:space:]]}"}"
# Does this timestamp exist in the PRE-LIST
timestamp=${timeline:0:19}
preCt=$(sed -n "s/^$timestamp.\(.*\)/\1/p" "$preList" |wc -l)
if [ "$preCt" -eq "0" ] ; then
sqlite3 "$appdb" "INSERT INTO Tmain (time,title,note) VALUES('$timestamp','$title','$note');"
elif [ "$preCt" -gt "1" ] ; then
excod=3
zenity --error --text "$preCt duplicate timestamps found. \
\nThis is an 'alpha' problem! \
\n\n Exiting with code $excod"
exit $excod
else
# TODO: At it currently stands, it is only known that "something" has changed,
# but not which rows have been effected. (Just update them all, for now.)
id=$(sed -n "s/^$timestamp.\(.*\)/\1/p" "$preList")
sqlite3 "$appdb" "UPDATE Tmain SET note='$note' WHERE id='$id';"
# Remove line from PRE-LIST
sed -i -e "/^$timestamp.*$/d" "$preList"
fi
}
############################################################################
sep="∘" # Field seperator
sepmulti="∘∘∘∘∘∘∘∘∘∘∘∘∘∘∘∘∘∘∘∘∘∘∘∘"
sepfirst="∘∘(write∘new∘notes∘below∘this∘line)∘∘"
appnam="tinotes"
appdir="$HOME/.$appnam"
appdb="$appdir/$appnam.db"
appsql="$appdir/$appnam.sql"
apptxt="$appdir/$sep$sep$sep$appnam$sep$sep$sep"
preList="$appdir/$appnam.pre"; echo -n>"$preList"
tiwid=0 # Check for a currently running Instance of the "Leafpad" window...
tiwid=$(wmctrl -l |sed -n "s/\([^ ]\+\) \+[^ ]\+ \+[^ ]\+ \*\?$(basename $apptxt)$/\1/p")
if [ "${tiwid:0:2}" == "0x" ] ; then
# Warn of the need to finalize an already-running instance of this script
zenity --warning --text "You must first finalize a previously opened \n\t 'tinotes' window.\
\n\n To activate the window, select 'OK'"
# 'wmctrl' can only activate via a title
# ..and it is case-insensitive and wildcarded!!
# so use 'xdotool'
xdotool windowactivate --sync $(($tiwid))
exit
fi
#################################################################################################################################################
[ "$clearAllDataAndStartAgain" = "true" ] && [ -d "$appdir" ] && rm -rf "$appdir" # Typically for TESTING ONLY; Remove all data,and start afresh!
#################################################################################################################################################
# First-time create app's main directory
[ ! -d "$appdir" ] && mkdir "$appdir"
# First-time Create the Tmain table
[ ! -f "$appdb" ] && sqlite3 "$appdb" "create table Tmain (id INTEGER PRIMARY KEY,time DATE,title TEXT,note TEXT);"
# Get the active-window's title
# =============================
activeT=$(xwininfo -id "$(xdotool getactivewindow)" |sed -n \
"2s/^xwininfo: Window id: \(0x[[:xdigit:]]\+\) \x22\(.*\)\x22$/\2/p")
# Does a previous row of the same title already exist?
# ====================================================
# First, prepare a new/"empty" note entry
echo "$activeT" >"$apptxt"
echo -e $(date '+%Y-%m-%d %H:%M:%S' |tr -d '\n')" $sep$appnam$sepfirst\n\n\n">>"$apptxt"
# Count existing rows for this title
if [ $(sqlite3 "$appdb" "SELECT COUNT(title) FROM Tmain WHERE title = '$activeT';") -gt 0 ] ; then
# Previous notes FOUND for this window title
# Make a list of timestamps to match-off against any user mods
sqlite3 "$appdb" "SELECT time,id FROM Tmain WHERE title='$activeT';" >"$preList"
# Build and Run the query to construct the "timeline"
echo -e ".separator "$sep"\n\
SELECT time||' $sep$appnam$sepmulti','\n\n'||note||'\n' FROM Tmain WHERE title='$activeT' order by time desc;">"$appsql"
sqlite3 "$appdb" <"$appsql">>"$apptxt"
fi
# Present the notes to the user (get the "before" md5sum, to compare with user's access/mods)
md5bef=$(md5sum "$apptxt" |sed "s/\([[:xdigit:]]\+\).*/\1/")
leafpad "$apptxt" # The script waits for the user to close "leafpad"
md5aft=$(md5sum "$apptxt" |sed "s/\([[:xdigit:]]\+\).*/\1/")
# Check for any modifications to the notes
if [ "$md5bef" == "$md5aft" ] ; then
# No changes have been made.
exit 0
fi
# The notes have been modified. Commit the changes!
# It's time to analyze the changes, and tidy up.
# Remove leading and trailing blank lines (per timestamp).
# Delete rows for which the timestamp has been removed.
# Update the table for all the remaining rows.
note=""
lnCt=0
while read line ; do
lnCt=$((lnCt+1))
[ "$lnCt" -eq "1" ] && continue # The first line is a throw-away copy of the "title"
# Find timeline. Any leading data is lost. (It shouldn't be there... common-sense!)
if [[ "$line" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}\ [0-9]{2}:[0-9]{2}:[0-9]{2}\ ∘.*∘$ ]] ; then
# FOUND timeline
if [ "$note" != "" ] ; then
FinalizeNote "$activeT" "$note" "$timeline" "$preList"
fi
note=""
timeline=$line
elif [ "$line" = "" ] ; then
if [ "$note" != "" ] ; then
note="$note$line"$'\n' # append this blank line
fi
else
note="$note$line"$'\n' # append this non-blank line
fi
done <"$apptxt"
#
if [ "$note" != "" ] ; then
FinalizeNote "$activeT" "$note" "$timeline" "$preList"
fi
# Delete rows for timestamps still in the PRE-LIST
while read line ; do
eval $(echo "$line" |sed -n "s/.*|\([0-9]\+\)$/id=\1/p")
sqlite3 "$appdb" "DELETE FROM Tmain WHERE id='$id';"
done <"$preList"
exit
############################################################################
Кроме того, что Оли сказал о написании переносимых скриптов (и взлома на coreutils), есть еще две ситуации, когда страницы руководства POSIX могут оказаться полезными:
Если вы установили переменную среды POSIXLY_CORRECT (во что угодно, она может быть даже пустой), многие утилиты GNU и некоторые другие программы будут вести себя в мода, указанная POSIX, даже когда разработчики не видели причин, по которым пользователи, скорее всего, захотят этого поведения.
Это не приводит к тому, что ваша система ведет себя как настоящая ОС, совместимая с POSIX. Ядро Linux, GNU libc и многие инструменты userlands все специально разработаны для совместимости с POSIX, только когда это более полезно, чем вредно. Это одна из причин того, что системы GNU / Linux, такие как Ubuntu, широко считаются не системами Unix.
На поведение ls влияет хакинг , но это [d7 ], только когда это делает более полезным, чем вредоносное , зависит от того, установлен или нет POSIXLY_CORRECT. (Вы можете проверить это, проверив исходный код, например, 13.04: ls-ls.c, coreutils и ls.c не ссылаются на эту переменную среды.)
Но некоторые другие утилит затронуты. Например, утилита df печатает информацию об использовании диска для всех смонтированных устройств. Обычно Ubuntu df (разделенный GNU coreutils) показывает это в 1 килобайтах. С установленным POSIXLY_CORRECT, он показывает его в блоках 512 B (т.е. полукилограмм). Это поведение требуется по стандарту POSIX, но ls-ls.c , поэтому оно не является значением по умолчанию.
ek@Kip:~$ df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda8 15481840 11816640 2878768 81% /
udev 1020748 12 1020736 1% /dev
tmpfs 412840 5156 407684 2% /run
none 5120 0 5120 0% /run/lock
none 1032100 240 1031860 1% /run/shm
none 102400 32 102368 1% /run/user
/dev/sda6 245679 159043 73529 69% /boot
/dev/sda9 31458256 10024972 19835284 34% /home
/dev/sdd1 1922859824 1687175656 138008496 93% /media/ek/Noether
/dev/sdc1 1922859824 1700447368 124736784 94% /media/ek/Baker
/dev/sdb1 1922859824 1782944724 42239428 98% /media/ek/Spinoza
ek@Kip:~$ POSIXLY_CORRECT= df
Filesystem 512B-blocks Used Available Use% Mounted on
/dev/sda8 30963680 23573440 5817376 81% /
udev 2041496 24 2041472 1% /dev
tmpfs 825680 10312 815368 2% /run
none 10240 0 10240 0% /run/lock
none 2064200 480 2063720 1% /run/shm
none 204800 64 204736 1% /run/user
/dev/sda6 491358 318086 147058 69% /boot
/dev/sda9 62916512 20049944 39670568 34% /home
/dev/sdd1 3845719648 3374351312 276016992 93% /media/ek/Noether
/dev/sdc1 3845719648 3400894736 249473568 94% /media/ek/Baker
/dev/sdb1 3845719648 3565889448 84478856 98% /media/ek/Spinoza
Иногда страница руководства POSIX является единственной доступной. Например, команда cd является встроенной оболочкой. Он предоставляется разными оболочками и немного отличается от оболочки к оболочке (в этом случае разные оболочки иногда делают cd принимающими разные ls.c ).
Интерактивная оболочка по умолчанию в Ubuntu есть bash, и вы можете получить информацию о cd в shell builtin . Но если вы хотите использовать справочную страницу только для cd, то нет исполняемого файла cd (нет единой универсальной, не зависящей от оболочки команды cd).
Но команда cd обязательная часть стандарта POSIX - оболочки должны реализовать его, а стандарт POSIX «знает» о том, что он требует. Таким образом, man-страница POSIX для cd возможна и существует.
Поиск cd на возможен для man-страницы POSIX для cd. показывает POSIX страницу руководства и две другие. Это, кстати, еще один пример нескольких страниц с одним и тем же именем. Что другие? Один из них - это cd команда может . Другой - это драйвер CD-ROM в операционной системе FreeBSD. Ручные страницы для FreeBSD иногда полезны для пользователей Ubuntu, поэтому их можно установить из целой коллекции, в том числе man 4 cd (ни одна из страниц руководства FreeBSD, скорее всего, не будет полезной для пользователей Ubuntu, также не использующих FreeBSD). [!d25 ]
Возможно, вам интересно, почему показывает страницу руководства POSIX и две другие страницы руководства в Ubuntu. В конце концов, в отличие от Ubuntu (и многих других ОС, таких как FreeBSD), Plan 9 даже не является операционной системой в стиле Unix, хотя, как говорит Оли, есть некоторые общие черты.
Причина в том, что Инструменты 9 пользовательского интерфейса Plan 9 (базовый набор инструментов, соответствующих очень грубоватым) были перенесены в Unix-подобные системы, поэтому их можно запускать на таких ОС, как Ubuntu.
Некоторые (не все) инструменты Plan 9, доступные для Ubuntu, имеют то же имя, что и инструменты Ubuntu , и выполнять те же или подобные функции.
Одна из причин наличия инструментов Plan 9 в Ubuntu заключается в том, что некоторые из них не соответствуют непосредственно любому инструменту Ubuntu (но могут все еще нуждаться в инструментах, которые do, для интероперабельности).
Еще одна причина заключается в поддержке программного обеспечения, которое зависит от инструментов Plan 9. Например, диспетчер окон wmii был упакован для Ubuntu (и доступен в официальных источниках программного обеспечения Ubuntu); этот Один пакет зависел от 9base.