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-check (2504 bytes)

1 #!/bin/sh
2 
3 # bm-check: report dead and permanently moved links.
4 #
5 #     bm-check                    the default bookmark file
6 #     bm-check file ...           these files ("-" is stdin)
7 #     bm --tag code --list | bm-check -
8 #
9 # Reads bookmark lines (only the first field matters, so a plain list of URLs
10 # works too) and prints, for each link that is in trouble,
11 #
12 #     status<tab>url[<tab>new location]
13 #
14 # where status is the HTTP status, or 000 when there was no answer. 301 and
15 # 308 are reported because the bookmark should be updated. Exits 1 when it
16 # printed anything.
17 
18 probe='%{http_code} %{redirect_url}'
19 
20 check () {
21     res=$(curl -sI --max-time 10 -A 'Mozilla/5.0' -o /dev/null -w "$probe" \
22           -- "$1" 2>/dev/null)
23     case ${res%% *} in
24         403|405|000|'')
25             # Some servers refuse HEAD; ask for the first byte instead.
26             res=$(curl -s -r 0-0 --max-time 10 -A 'Mozilla/5.0' -o /dev/null \
27                   -w "$probe" -- "$1" 2>/dev/null)
28             ;;
29     esac
30     code=${res%% *}
31     case $code in
32         301|308) printf '%s\t%s\t%s\n' "$code" "$1" "${res#* }" ;;
33         2*|3*)   ;;
34         *)       printf '%s\t%s\n' "${code:-000}" "$1" ;;
35     esac
36 }
37 
38 case ${1-} in
39     -h|--help) sed -n '3,16s/^# \{0,1\}//p' "$0"; exit 0 ;;
40 esac
41 
42 command -v curl >/dev/null 2>&1 || { printf 'bm-check: needs curl\n' >&2; exit 1; }
43 [ $# -gt 0 ] || set -- "${BOOKMARKS:-${XDG_DATA_HOME:-$HOME/.local/share}/sbm/bookmarks}"
44 
45 # Eight probes in flight until the list runs out, like xargs -P 8, with a
46 # FIFO as the semaphore: it starts out holding eight tokens, a probe takes one
47 # before it starts and puts it back when it is done. Opening a FIFO blocks
48 # until the other end is opened too, hence the helper that opens it for
49 # writing while we open it for reading. Every report is one short line from
50 # one printf, so concurrent probes do not garble each other.
51 fifo=${TMPDIR:-/tmp}/bm-check.$$
52 mkfifo -m 600 "$fifo" || { printf 'bm-check: cannot create %s\n' "$fifo" >&2; exit 1; }
53 trap 'rm -f "$fifo"' EXIT INT TERM
54 : > "$fifo" &
55 # shellcheck disable=SC2094  # both ends of the FIFO, on purpose
56 exec 3< "$fifo" 4> "$fifo"
57 rm -f "$fifo"
58 printf '\n\n\n\n\n\n\n\n' >&4
59 
60 bad=$(cat -- "$@" | awk -F'\t' 'NF && !/^#/ { print $1 }' | {
61     while IFS= read -r url; do
62         # shellcheck disable=SC2034  # the token is only waited for
63         read -r token <&3
64         { check "$url"; echo >&4; } &
65     done
66     wait
67 })
68 [ -z "$bad" ] && exit 0
69 printf '%s\n' "$bad"
70 exit 1