You are not logged in.
Some people wanted me to improve it, so how's this for size
#!/bin/bash
export BOOKMARK_DB=${HOME}/.bm.db
bm(){
local special='=';
local add='+';
local remove='-';
## end easy edit.
local unsafe="s/'/''/g" # the sed clean up replacement
local arg1="$(echo "$1" | sed "${unsafe} " )" # a copy of $1 that's safe to work with
local arg2="$(echo "$2" | sed "${unsafe} " )" # a copy of $2 that's safe to work with
local dinit=0; # are we doing the database init before anything else?
## Check the database for errors, if there is an error we force init.
echo ".schema bookmarks;" | sqlite3 "$BOOKMARK_DB" || {
echo "Database cannot be checked." >&2
echo "Recreating database, your bookmarks will be lost :("
dinit=1;
}
if [[ "$dinit" = "1" || "$arg1" = "${special}init" ]]; then
rm "$BOOKMARK_DB"
echo "CREATE TABLE bookmarks(bookmark text primary key, path text);" |
sqlite3 "${BOOKMARK_DB}" || {
echo "ERROR: UNABLE TO CREATE DATABASE '${BOOKMARK_DB}'"
return 101
}
echo "Database created."
[[ $dinit = 0 ]] && return 0; # quit early if all we're doing is initing.
fi
# normal argument scanner:
case $arg1 in
${special}l|${special}list)
echo "SELECT bookmark FROM bookmarks;" |
sqlite3 "${BOOKMARK_DB}" ;;
${special}h|${special}help|${special}\?)
echo "USAGE: $0 ARGUMENT
Where argument is either a bookmark to CD to or beginning with a special character:
${special}
Operates all special commands such as 'help', 'init', 'query' and 'list'
${add}
Adds a new bookmark, optional second argument for path.
${remove}
Removes the bookmark specified.
Example usage:
Force creation of a new database
(should be done automatically on first run).
\$ $0 ${special}init
Add the bookmark 'b' to the directory 'bar'
\$ $0 ${add}b bar
Add the bookmark 't' to /tmp
\$ $0 ${add}t /tmp
List all bookmarks
\$ $0 ${special}l
Query the path 't' points to
\$ $0 ${special}q t
Remove the bookmark 't'
\$ $0 ${remove}t
Special files:
${BOOKMARK_DB}
The bookmark database." ;;
${special}q|${special}query)
[ -z $2 ] && {
echo "You must specify a bookmark to query." >&2
return 22
}
echo "SELECT path FROM bookmarks WHERE bookmark='${arg2}';" |
sqlite3 "${BOOKMARK_DB}" ;;
$special*)
echo "Unrecognised command." >&2
return 21
;;
$add*)
arg1="${arg1:1}"
if [[ "${arg1:0:1}" = "$add" || "${arg1:0:1}" = "$special" || "${arg1:0:1}" = "$remove" ]]; then
echo "Error, bookmark name begins with a special character." >&2
return 12;
else
if [ -z "$2" ]; then
arg2="$(pwd | sed "${unsafe} " )"
elif [ ! -d "$2" ]; then
echo "Path invalid." >&2
return 11
fi
echo "INSERT OR REPLACE INTO bookmarks VALUES('${arg1}','${arg2}');" |
sqlite3 "${BOOKMARK_DB}"
fi ;;
$remove*)
arg1="${arg1:1}"
echo $( echo "PRAGMA count_changes = true; DELETE FROM bookmarks WHERE bookmarks.bookmark='${arg1}';" |
sqlite3 "${BOOKMARK_DB}" ) "result(s) deleted." ;;
*)
local path="$(echo "SELECT path FROM bookmarks WHERE bookmark='${arg1}';" |
sqlite3 "${BOOKMARK_DB}")" #"
if [ -z "${path}" ]; then
echo "Bookmark doesn't exist.
Are you looking for help? Consult '$0 =help'" >&2
return 2
elif [ -d "${path}" ]; then
cd "${path}"
else
echo "Bad path ${path}" >&2
return 1
fi
;;
esac
}
It's completely backwards compatible, but also completely rewritten, so back up your database first if you don't want to be worried about losing it.
Like with the previous version it needs to be sourced or included in your .bashrc file before it can be used.
This new version features a few major modifications, there's some special commands(for now list, help, query and init), the exact modifiers can easily be changed(they could previously if you didn't mind looking for it) and there is such much cleaner logic in play.
I've also fixed a couple of bugs:
Single quotes no longer ruin input.
You cannot enter a bookmark name that begins with a special character
If the database is corrupt or doesn't exist the script stops to fix the problem first, if it cannot it returns an error.
Return codes(in case you ever want to check them):
0 - Everything went exactly as expected.
code < 10 = seeking
1 - Path to directory that doesn't exist associated with bookmark
2 - Bookmark doesn't exist
20 > code > 10 = add
11 - Path doesn't work
12 - Bookmark name is invalid
100 > code > 20 = special commands
21 - Unrecognised command
22 - No bookmark passed to query.
101 - Unable to create database.
Last edited by scragar (2010-03-12 20:04:04)
Offline
Just to say this has proved to be very useful, thanks. One suggestion might be tab-completion.
It also got me thinking whether there is a standard bash "interface" to sqlite... i.e. a set of reusable scripts and also the circle argument of Databases vs plain-text
Offline
what is this? what's the goal?
< Daenyth> and he works prolifically
4 8 15 16 23 42
Offline
Its a command line bookmarking script, "bookmarking" in the sense of directory paths, not web pages (if that's your question?).
For example:
$ bm init ## create database
$ bm +h ~ ## create one for home
$ bm +d ~/Desktop ## one for my Desktop
$ bm +m ~/music ## for my music
$ pwd
/home/scragar/Desktop/Sorted/iso
$ bm +iso ## for the current directory
$ bm h
$ pwd
/home/scragar
$ bm m
$ pwd
/home/scragar/music
$ bm iso
$ pwd
/home/scragar/Desktop/Sorted/iso
$ ## Now for the really fun stuff
$ bm +t ~/test
$ bm t
Unable to CD to bookmark 't'
Loaded path ~/test
$ bm -t
$ bm t
bookmark not recognised.
(source)
Last edited by gladstone (2010-04-30 16:06:13)
Offline
Are there advantages in using this (an sql backend) instead of symlinks (filesystem backend)?
I mean, why don't just use a bunch of aliases/scripts which do "ln -s $1 /bookmarkdir/$2" , "unlink /bookmarks/$1" and so on?
Help me to improve ssh-rdp !
Retroarch User? Try my koko-aio shader !
Offline
i wonder if something like this could be implemented...
$ bm init
$ bm +h ~
$ bm +m h/music
$ bm ls h
music foo bar
$ bm mv h/{foo,bar} m/
$ ls ~/music
artist-1 artist-2 foo bar
now _that'd_ be cool.
*and i don't mean built-in bm ls and mv commands, i mean prefix _any_ command with bm and it'll resolve the bookmarks before executing.
//github/
Offline
I'm having the following issue with bm: the help text replaces what should say "bm" with "/bin/bash". The mistake appears to be analogous to this one, but I don't know how to fix it (in any way elegant).
e.g.: USAGE: /bin/bash ARGUMENT
Overall functionality itself is intact, but this problem is a little annoying. Thanks again for the wonderful script.
Registed Linux User 483618
Offline
I'm having the following issue with bm: the help text replaces what should say "bm" with "/bin/bash".
That's because bm is loaded as a shell function (probably sourced in your .bashrc) and bm uses the $0 positional parameter to prefix (what should be) the programs name in the help text. You can display all defined functions with: `declare -f | less`.
Since bash calls the function itself, $0 is set to "/bin/bash". The easiest way to fix it would probably be to replace all occurrences of "$0" with "bm".
p.s. you might also like to check out autojump. Instead of bookmarking your directories manually, it gradually builds up a database of the directories you cd to frequently.
Offline
p.s. you might also like to check out autojump. Instead of bookmarking your directories manually, it gradually builds up a database of the directories you cd to frequently.
Thanks for the suggestion, but I'm now using ZSH, and I put my favorite directories in my CDPATH. If I was still using bash, I would definitely still be using bm .
Registed Linux User 483618
Offline