X-Git-Url: https://git.xandkar.net/?a=blobdiff_plain;f=home%2Flib%2Flogin_functions.sh;h=193f4be374266469790c1ae46aee48bedf0e698b;hb=917869f84b6a138745f0a66d1499ea89e3810656;hp=3ea0e1d61f5ccaa73ad545bab436ed1e600e3189;hpb=56b5d8cf0df6d56c19d7b510748429da19137335;p=khome.git diff --git a/home/lib/login_functions.sh b/home/lib/login_functions.sh index 3ea0e1d..193f4be 100644 --- a/home/lib/login_functions.sh +++ b/home/lib/login_functions.sh @@ -1,6 +1,84 @@ # -## ws: web search +## open : string -> unit +## +## Fork xdg-open so we don't block current terminal session when opening +## things like pdf files. For example: +## +## open book.pdf +## +open() { + (xdg-open "$1" &) & +} + +## notify_done : unit -> unit +notify_done() { + local -r _status_code="$?" + local -r _program="$1" + local _timestamp + _timestamp="$(timestamp)" + local -r _msg="$_timestamp [$_program] done " + if [[ "$_status_code" -eq 0 ]] + then + notify-send -u normal "$_msg OK: $_status_code" + else + notify-send -u critical "$_msg ERROR: $_status_code" + fi +} + +## p : string -> unit +p() { + awk \ + -v _s="$1" \ + ' + BEGIN {_s = tolower(_s)} + + # TODO fzf/dmenu select instead of searching: + /^[a-zA-Z]/ && tolower($1) ~ _s && NF >= 2 { + n++ + s = $1 + p = $NF + if (NF == 2) { + e = "" + u = "" + } else if (NF == 3) { + e = $2 + u = "" + } else { + e = $2 + u = $3 + } # TODO What would NF > 4 mean? + + printf("%d [O] s:\"%s\", e:\"%s\", u:\"%s\"\n", n, s, e, u) > "/dev/stderr" + if (match(u, "@")) { + tmp = e + e = u + u = tmp + printf("%d [C] s:\"%s\", e:\"%s\", u:\"%s\"\n", n, s, e, u) > "/dev/stderr" + } + + printf "%s", p # XXX Intentionally avoiding newline in the result. + } + + END { + if (n == 1) { + exit 0 + } else if (n == 0) { + printf "[ERROR] Found nothing.\n" > "/dev/stderr" + exit 1 + } else if (n > 1) { + # TODO fzf-select which of the records the user (ahem, me) wants. + printf "[WARNING] Found more than one record.\n" > "/dev/stderr" + exit 0 + } + } + ' \ + ~/._p/p \ + | xsel -i -b -t 30000 +} + +## web search +## ws : string -> unit ws() { local line search_string0 search_string @@ -17,11 +95,15 @@ ws() { firefox --search "$search_string" } + +## dictionary +## d : string -> string list d() { local -r word=$(fzf < /usr/share/dict/words) dict "$word" } +## shell_activity_report : (mon | dow) -> string list shell_activity_report() { # TODO: optional concrete number output # TODO: optional combinations of granularities: hour, weekday, month, year @@ -119,6 +201,7 @@ shell_activity_report() { }' } +## top_commands : unit -> (command:string * count:number * bar:string) list top_commands() { history \ | awk ' @@ -153,10 +236,13 @@ top_commands() { | column -t } -# Top Disk-Using directories -# TODO: Consider using numfmt instead of awk +## Top Disk-Using directories +## TODO: Consider using numfmt instead of awk +## tdu : path-string -> (size:number * directory:path-string) list tdu() { - du "$1" \ + local -r root_path="$1" + + du "$root_path" \ | awk ' { size = $1 @@ -182,9 +268,10 @@ tdu() { # A slight optimization: head can exit before traversing the full input. } -# Top Disk-Using Files +## Top Disk-Using Files +## tduf : path-string list -> (size:number * file:path-string) list tduf() { - find "$1" -type f -printf '%s\t%p\0' \ + find "$@" -type f -printf '%s\t%p\0' \ | sort -z -n -k 1 \ | tail -z -n 50 \ | gawk -v RS='\0' ' @@ -198,13 +285,12 @@ tduf() { } # Most-recently modified file system objects +## recent : ?(path-string list) -> path-string list recent() { # NOTES: - # - intentionally not quoting the parameters, so that some can be ignored - # if not passed, rather than be passed to find as an empty string; # - %T+ is a GNU extension; # - gawk is able to split records on \0, while awk cannot. - find $@ -printf '%T@ %T+ %p\0' \ + find "$@" -printf '%T@ %T+ %p\0' \ | tee >(gawk -v RS='\0' 'END { printf("[INFO] Total found: %d\n", NR); }') \ | sort -z -k 1 -n -r \ | head -n "$(stty size | awk 'NR == 1 {print $1 - 5}')" -z \ @@ -217,23 +303,28 @@ recent() { }' } +## recent_dirs : ?(path-string list) -> path-string list recent_dirs() { - recent "$1" -type d + recent "$@" -type d } +## recent_files : ?(path-string list) -> path-string list recent_files() { - recent "$1" -type f + recent "$@" -type f } +## pa_def_sink : unit -> string pa_def_sink() { pactl info | awk '/^Default Sink:/ {print $3}' } +## void_pkgs : ?(string) -> json void_pkgs() { curl "https://xq-api.voidlinux.org/v1/query/x86_64?q=$1" | jq '.data' } -# Colorful man +## Colorful man +## man : string -> string man() { # mb: begin blink # md: begin bold @@ -254,15 +345,20 @@ man() { command man "$@" } -# new experiment +## new experiment +## x : string list -> unit x() { cd "$(~/bin/x $@)" || kill -INT $$ } +## ocaml repl +## hump : unit -> unit hump() { ledit -l "$(stty size | awk '{print $2}')" ocaml $@ } +## search howtos +## howto : unit -> string howto() { cat "$(find ~/arc/doc/HOWTOs -mindepth 1 -maxdepth 1 | sort | fzf)" } @@ -272,14 +368,15 @@ _yt() { local -r uri="$2" local -r opts="$3" - local -r id=$(youtube-dlc --get-id "$uri") - local -r title=$(youtube-dlc --get-title "$uri" | sed 's/[^А-Яа-яA-Za-z0-9._-]/_/g') + local -r yt=youtube-dl + local -r id=$("$yt" --get-id "$uri") + local -r title=$("$yt" --get-title "$uri" | sed 's/[^А-Яа-яA-Za-z0-9._-]/_/g') local -r dir="${base_dir}/${title}--${id}" mkdir -p "$dir" cd "$dir" || kill -INT $$ echo "$uri" > 'uri' - youtube-dlc $opts -c --write-description --write-info-json "$uri" + "$yt" $opts -c --write-all-thumbnails --write-description --write-info-json "$uri" } yt_audio() { @@ -307,7 +404,7 @@ gh_clone() { mkdir -p "$gh_dir" cd "$gh_dir" || kill -INT $$ gh_fetch_repos "$gh_user_type" "$gh_user_name" \ - | jq --raw-output '.[] | select(.fork | not) | .git_url' \ + | jq --raw-output '.[] | select(.fork | not) | .clone_url' \ | parallel -j 25 \ git clone {} } @@ -328,6 +425,32 @@ gh_clone_repo() { git clone "$1" } +daily_todo_file_template() { +cat << EOF +=============================================================================== +$(date '+%F %A') +=============================================================================== + + +backlog +------------------------------------------------------------------------------- +EOF +} + +todo() { + local date + date="$(date +%F)" + local -r dir="$DIR_TODO/daily" + local -r file="$dir/$date.txt" + + mkdir -p "$dir" + if [ ! -f "$file" ] + then + daily_todo_file_template > "$file" + fi + cd "$DIR_TODO" && "$EDITOR" "$file" +} + work_log_template() { cat << EOF $(date '+%F %A') @@ -365,15 +488,6 @@ note() { vim -c 'set spell' "$DIR_NOTES/$(date +'%Y_%m_%d--%H_%M_%S%z')--$1.md" } -weather() { - local _weather_location - case "$1" in - '') _weather_location="$WEATHER_LOCATION";; - *) _weather_location="$1" - esac - curl "http://wttr.in/$_weather_location?format=v2" -} - _bt_devs_infos() { # grep's defintion of a line does not include \r, wile awk's does and # which bluetoothctl outputs @@ -652,33 +766,33 @@ status() { sudo -n netstat -tulnp \ | awk -v indent="${indent_unit}${indent_unit}" ' NR > 2 && ((/^tcp/ && proc = $7) || (/^udp/ && proc = $6)) { - protocol = $1 - addr = $4 - port = a[split(addr, a, ":")] - name = p[split(proc, p, "/")] - names[name] = 1 - protocols[protocol] = 1 - if (!seen[protocol, name, port]++) - ports[protocol, name, ++seen[protocol, name]] = port - } - - END { - for (protocol in protocols) { - printf "%s%s\t", indent, toupper(protocol) - for (name in names) { - if (n = seen[protocol, name]) { - sep = "" - printf "%s:", name - for (i = 1; i <= n; i++) { - printf "%s%d", sep, ports[protocol, name, i] - sep = "," - } - printf " " - } - } - printf "\n" - } - }' + protocol = $1 + addr = $4 + port = a[split(addr, a, ":")] + name = p[split(proc, p, "/")] + names[name] = 1 + protocols[protocol] = 1 + if (!seen[protocol, name, port]++) + ports[protocol, name, ++seen[protocol, name]] = port + } + + END { + for (protocol in protocols) { + printf "%s%s\t", indent, toupper(protocol) + for (name in names) { + if (n = seen[protocol, name]) { + sep = "" + printf "%s:", name + for (i = 1; i <= n; i++) { + printf "%s%d", sep, ports[protocol, name, i] + sep = "," + } + printf " " + } + } + printf "\n" + } + }' echo "${indent_unit}<->" @@ -716,32 +830,32 @@ ssh_invalid_by_addr() { ssh_invalid_by_day() { awk ' - BEGIN { - m["Jan"] = "01" - m["Feb"] = "02" - m["Mar"] = "03" - m["Apr"] = "04" - m["May"] = "05" - m["Jun"] = "06" - m["Jul"] = "07" - m["Aug"] = "08" - m["Sep"] = "09" - m["Oct"] = "10" - m["Nov"] = "11" - m["Dec"] = "12" - } - - /: Invalid user/ && $5 ~ /^sshd/ { - day = m[$1] "-" $2 - max++ - by_day[day]++ - } - - END { - for (day in by_day) - if ((c = by_day[day]) > 1) - printf "%d %d %s\n", c, max, day - } + BEGIN { + m["Jan"] = "01" + m["Feb"] = "02" + m["Mar"] = "03" + m["Apr"] = "04" + m["May"] = "05" + m["Jun"] = "06" + m["Jul"] = "07" + m["Aug"] = "08" + m["Sep"] = "09" + m["Oct"] = "10" + m["Nov"] = "11" + m["Dec"] = "12" + } + + /: Invalid user/ && $5 ~ /^sshd/ { + day = m[$1] "-" $2 + max++ + by_day[day]++ + } + + END { + for (day in by_day) + if ((c = by_day[day]) > 1) + printf "%d %d %s\n", c, max, day + } ' \ /var/log/auth.log \ /var/log/auth.log.1 \