Recently Written · git

sbm

dmenu bookmarks. Instantly fuzzy search thousands of bookmarks and plumb them. LOOKING FOR SUCKLESS SOFTWARE EDITION? GO TO sbm-suckless INSTEAD

git clone https://github.com/equwal/sbm

Log | Files | Refs


bm-migrate (3220 bytes)

1 #!/bin/sh
2 
3 # bm-migrate: convert a bookmark file from the old sbm format
4 #
5 #     URL description | tag tag
6 #
7 # to the tab separated one bm uses now
8 #
9 #     URL<tab>description<tab>tag tag
10 #
11 # The URL is the first word, the tags are whatever follows the last " | ", and
12 # a line without " | " has no tags. Comments, blank lines and lines that already
13 # contain a tab are passed through, so converting twice changes nothing.
14 
15 usage () {
16     cat <<'EOF'
17 usage: bm-migrate [-n] [file]
18   file   the bookmark file; defaults to $BOOKMARKS, then to
19          $XDG_DATA_HOME/sbm/bookmarks. "-" converts stdin to stdout.
20   -n     print the converted file instead of replacing it
21 The original is kept as <file>.bak (or .bak.1, .bak.2, ... if that exists).
22 EOF
23 }
24 
25 die () {
26     printf 'bm-migrate: %s\n' "$*" >&2
27     exit 1
28 }
29 
30 convert () {
31     awk '
32         /\t/ || /^#/ || NF == 0 { print; next }
33         {
34             url = $1
35             desc = $0
36             sub(/^[ ]*[^ ]+[ ]*/, "", desc)
37             tags = ""
38             if (match(desc, / \|[^|]*$/)) {
39                 tags = substr(desc, RSTART + 2)
40                 desc = substr(desc, 1, RSTART - 1)
41             }
42             gsub(/^ +| +$/, "", desc)
43             gsub(/^ +| +$/, "", tags)
44             printf "%s\t%s\t%s\n", url, desc, tags
45         }' "$@"
46 }
47 
48 # oldlines <file>: how many lines are still in the old format.
49 oldlines () {
50     awk '!/\t/ && !/^#/ && NF { n++ } END { print n + 0 }' "$1"
51 }
52 
53 dryrun=
54 while [ $# -gt 0 ]; do
55     case $1 in
56         -h|--help) usage; exit 0 ;;
57         -n|--dry-run) dryrun=1 ;;
58         -) break ;;
59         -*)
60             printf 'bm-migrate: unknown option: %s\n' "$1" >&2
61             usage >&2
62             exit 2
63             ;;
64         *) break ;;
65     esac
66     shift
67 done
68 if [ $# -gt 1 ]; then
69     printf 'bm-migrate: one file at a time\n' >&2
70     exit 2
71 fi
72 
73 file=${1:-${BOOKMARKS:-${XDG_DATA_HOME:-$HOME/.local/share}/sbm/bookmarks}}
74 
75 if [ "$file" = - ]; then
76     convert
77     exit
78 fi
79 
80 [ -f "$file" ] || die "no such file: $file"
81 [ -r "$file" ] || die "cannot read $file"
82 
83 if [ -n "$dryrun" ]; then
84     convert "$file"
85     exit
86 fi
87 
88 count=$(oldlines "$file")
89 if [ "$count" -eq 0 ]; then
90     printf 'nothing to migrate in %s\n' "$file"
91     exit 0
92 fi
93 
94 # Never overwrite an earlier backup: it may be the only copy of the original.
95 backup=$file.bak
96 n=0
97 while [ -e "$backup" ]; do
98     n=$((n + 1))
99     backup=$file.bak.$n
100 done
101 cp -p "$file" "$backup" || die "could not back up to $backup"
102 
103 # Through cat rather than mv, so that a symlinked bookmark file stays a symlink
104 # and keeps its permissions.
105 # Beside the file if that directory can be written to, else in $TMPDIR;
106 # noclobber (O_EXCL) keeps a planted file or symlink from being followed.
107 tmp=
108 for candidate in "$file.tmp.$$" "${TMPDIR:-/tmp}/sbm.$$.${file##*/}"; do
109     if (umask 077; set -C; : > "$candidate") 2>/dev/null; then
110         tmp=$candidate
111         break
112     fi
113 done
114 [ -n "$tmp" ] || die 'cannot create a temporary file'
115 trap 'rm -f "$tmp"' EXIT INT TERM
116 if ! convert "$backup" > "$tmp" || ! cat "$tmp" > "$file"; then
117     die "could not rewrite $file; the original is in $backup"
118 fi
119 
120 printf 'migrated %d lines in %s (original kept as %s)\n' "$count" "$file" "$backup"