diff options
| -rw-r--r-- | README | 4 | ||||
| -rwxr-xr-x | addemup | 125 | ||||
| -rwxr-xr-x | bsgrep | 77 | ||||
| -rw-r--r-- | lcd.sh | 23 | ||||
| -rwxr-xr-x | litterbox | 465 | ||||
| -rwxr-xr-x | slacklog | 3 | ||||
| -rwxr-xr-x | stealvim | 98 | ||||
| -rwxr-xr-x | termbin | 44 | ||||
| -rwxr-xr-x | tolatin | 8 | ||||
| -rwxr-xr-x | uleft | 25 | ||||
| -rwxr-xr-x | vol | 110 |
11 files changed, 905 insertions, 77 deletions
@@ -1,5 +1,6 @@ Stuff from my ~/bin directory. +addemup - add up numbers in stdin, files, or command line args; print total. bchunkmulti - wrapper for bchunk, to support multiple .bin files bkt - count repeats in input, show percentage/graph/etc calc_bitrate.pl - scan a DVD, calculate bitrate for ripping @@ -19,8 +20,10 @@ fraktur.pl - convert text to unicode fraktur/blackletter freqnote.pl - convert a frequency in Hz to the nearest note gammatrip.sh - randomly change gamma in X, crude simulation of an acid trip imagebin - pastebin an image +lcd.sh - "linked cd" for multiple terminals. lddsafe - https://github.com/rg3/lddsafe/ (local copy here) lddtree - show library dependencies as a tree +litterbox - upload files/directories to litter.catbox.moe mkclick.pl - generate a click track at a given tempo netqiv - wget and display an image file noobfarm2fortune.sh - scrape noobfarm.org, create fortune(6) file (no longer works!) @@ -38,6 +41,7 @@ slacklog - show Slackware ChangeLog slacksrc - download source directory of an official Slackware package slacktopic.pl - set ##slackware /topic from Slackware ChangeLog smartfmt - wrapper for fmt, ignores invariant prefixes +stealvim - take over a vim process remotely, with reptyr termbin - paste a file or stdin to termbin.com uleft - start urxvt with my preferred settings unfb2 - poor man's FictionBook2 to HTML or plain text converter @@ -0,0 +1,125 @@ +#!/usr/bin/perl -w + +use POSIX 'round'; +use Getopt::Std; +$Getopt::Std::STANDARD_HELP_VERSION++; + +$VERSION = "0.0.1"; +($SELF = $0) =~ s,.*/,,; + +sub VERSION_MESSAGE { + print "$SELF $VERSION\n"; +} + +sub HELP_MESSAGE { + print <<EOF; +$SELF - add up numbers in stdin, files, or command line args; print total. + +Usage: $SELF [-a] [-i] [-m] [args ...] + +By default, lines are read from standard input or the files given as +arguments. All numbers (integers, floating point, or hexadecimal with +leading 0x) found in the input are added together, and the total is +printed to stdout. + +Options: + -a Treats the arguments as numbers to add, rather than filenames. + -i Integers only. Any fractional part is truncated (use -r to round). + -m Also print the mean (average) of the numbers read. + -M Print only the mean (not the total). + -r Round to nearest integer (implies -i). + -h, --help + Print this usage message and exit. + -v, --version + Print version number and exit. + +Written by B. Watson <urchlay\@slackware.uk>, licensed WTFPL. +EOF +} + +# This regular expression doesn't recognize numbers without +# a digit before the decimal point, such as .01 or -.123. However, +# before this is used, the caller puts a 0 in the right place for +# such numbers. +# Doesn't the regex syntax with /x and comments remind you of +# assembly language? +$re = qr { + ( # EITHER: + (?: # hex number, + 0[xX] # leading 0x or 0X required, + [0-9a-fA-F]+ # hex digits, case insensitive. + ) + | # OR: + (?: # decimal number, + [-+]? # with optional leading sign, + \d+ # at least one digit required left of the decimal point, + (?:\.\d+)? # optional decimal point with trailing digits, + (?: # MAYBE: + [eE] # optional "e" or "E" for scientific notation, + [-+]? # optional exponent sign, + \d+ # at least one exponent digit, + )? # ...but the whole exponent part is optional! + ) + ) +}x; + +getopts('aihmMrv', \%opt) || exit 1; + +VERSION_MESSAGE(), exit(0) if $opt{v}; +HELP_MESSAGE(), exit(0) if $opt{h}; + +$opt{i} = 1 if $opt{r}; + +$sum = $count = 0; + +if($opt{a}) { + for(@ARGV) { + $sum += $_ for extract_numbers(); + } +} else { + while(<>) { + $sum += $_ for extract_numbers(); + } +} + +print $sum . "\n" unless $opt{M}; +if($opt{m} || $opt{M}) { + if($count) { + $avg = $sum / $count; + $avg = to_int($avg) if $opt{i}; + } else { + # always print an average, even if no numbers were read. + $avg = 0; + } + print $avg . "\n"; +} +exit 0; + +### +# Extract all the numbers in $_, return them an in array. +sub extract_numbers { + my @ret; + + # Handle numbers like .12 or -.99 by inserting a 0 before the . + s/(^|\D)(\.\d)/$1 . "0" . $2/ge; + + for(/$re/gc) { + $_ = hex $_ if /^0[xX]/; + $_ = to_int($_) if $opt{i}; + push @ret, $_; + $count++; + } + + return @ret; +} + +sub to_int { + warn "was: $_\n"; + if($opt{r}) { + $_ = round($_); + } else { + $_ = int $_; + } + warn "now: $_\n"; + return $_; +} @@ -22,7 +22,7 @@ $SIG{__WARN__} = sub { # from the 'while(<>)' or File::Find. if($m !~ /^$self:/) { $m = "$self: $m"; - $ret = 2 unless $opt{s}; + $ret = 2 unless $opt{q}; } print STDERR $m unless $opt{s}; @@ -315,22 +315,29 @@ select lines that match all of the patterns; the default is to select lines that match any of the patterns. This option doesn't exist in B<grep>. +=item -q + +Quiet: don't write to standard output. Exit status will be zero if +a match was found, even if there were errors. This doesn't prevent +warnings/errors being printed to standard error; use B<-s> to silence +those. Same as B<grep>. + =item -r Recursively read all files under each directory, following symlinks only if they're on the command line. If no files or directories are given, reads the current directory. Same as B<grep>. -=item -v - -Print only lines that do I<not> match (same as B<grep>). - =item -s Silence warnings (same as B<grep>). This includes error messages about unreadable files as well as warnings about the input (see B<DIAGNOSTICS>, below). +=item -v + +Print only lines that do I<not> match (same as B<grep>). + =back =head1 EXAMPLE @@ -409,7 +416,7 @@ to be Unicode, it will be assumed ISO-8859-1, and converted to Unicode. =head1 EXIT STATUS 0 if there were any matches, 1 if there were none, or 2 if there -were errors (e.g. nonexistent file). However, with B<-s>, the exit +were errors (e.g. nonexistent file). However, with B<-q>, the exit status will be 0 or 1 even if there were errors. This is the same as B<grep>'s exit status. @@ -445,3 +452,61 @@ under the WTFPL: Do WTF you want with this. B<grep>(1), B<perl>(1) =cut + +__END__ + +implemented: + --help + -V, --version + -F, --fixed-strings + -e PATTERNS, --regexp=PATTERNS + -i, --ignore-case + -v, --invert-match + -q, --quiet, --silent + -s, --no-messages + -n, --line-number + -z, --null-data + -r, --recursive + -l, --files-with-matches + +todo: + -f FILE, --file=FILE + -y Obsolete synonym for -i. + -c, --count + -R, --dereference-recursive + -L, --files-without-match + -Z, --null + -A NUM, --after-context=NUM + -B NUM, --before-context=NUM + -C NUM, -NUM, --context=NUM + -H, --with-filename + -h, --no-filename + -w, --word-regexp + -x, --line-regexp + +do not implement: + -E, --extended-regexp + -G, --basic-regexp + -P, --perl-regexp + --no-ignore-case + +undecided: + --color[=WHEN], --colour[=WHEN] + -m NUM, --max-count=NUM + -o, --only-matching + -b, --byte-offset + --label=LABEL + -T, --initial-tab + --group-separator=SEP + --no-group-separator + -a, --text + --binary-files=TYPE + -D ACTION, --devices=ACTION + -d ACTION, --directories=ACTION + --exclude=GLOB + --exclude-from=FILE + --exclude-dir=GLOB + -I + --include=GLOB + --line-buffered + -U, --binary @@ -0,0 +1,23 @@ +# lcd.sh - "Linked" cd, for people who use multiple terminals. + +# Copy me to e.g. ~/.lcd.sh, then in your .bash_profile, .bashrc, +# or whatever shell startup script you use: + +# [ -e ~/.lcd.sh ] && source ~/.lcd.sh + +# Log out & back in, or close and restart all your terminal windows. + +# Now when you type a cd command in one shell, such as: +# cd /usr/src/linux-$( uname -r )/Documentation +# ...you can switch over to another terminal and type: +# lcd +# ...and now that terminal is cd'ed to the same directory. + +cd() { + builtin cd "$@" + pwd > ~/.lcd.dir +} + +lcd() { + [ -e ~/.lcd.dir ] && cd "$( cat ~/.lcd.dir )" +} diff --git a/litterbox b/litterbox new file mode 100755 index 0000000..ad730ab --- /dev/null +++ b/litterbox @@ -0,0 +1,465 @@ +#!/bin/bash + +# based on the API spec: https://litterbox.catbox.moe/tools.php + +VERSION="0.0.1" +SELF="$( basename $0 )" +APIURL="https://litterbox.catbox.moe/resources/internals/api.php" +URLS="" +EXPIRE="1" +DELAY="${DELAY:-2}" +UPLOAD_COUNT=0 +TMP="$( mktemp -t -d $SELF.XXXXXXXXXX )" +trap cleanup EXIT + +die() { + echo "$SELF: fatal: $@" 1>&2 + exit 1 +} + +warn() { + echo "$SELF: warning: $@" 1>&2 +} + +info() { + [ "$VERBOSE" = "1" ] && echo "$SELF: info: $@" 1>&2 +} + +check_path() { + type -p "$1" &>/dev/null +} + +cleanup() { + [ "$TMP" != "" ] && rm -rf "$TMP" +} + +usage() { + if ! check_path perldoc; then + warn "can't find perldoc on PATH, printing raw POD." + exec sed -n '/^=pod/,/^=cut/p' $0 + fi + + exec perldoc "$0" +} + +manpage() { + exec pod2man --stderr -s1 -c"UrchlaysStuff" -r$VERSION "$0" +} + +pluralize() { + echo -n "$1 $2" + [ "$1" != 1 ] && echo -n "s" +} + +delay() { + info "sleeping $DELAY sec between $1" + sleep "$DELAY" +} + +set_expiration() { + case "$1" in + 1|12|24|72) ;; # OK + *) die "invalid expiration time, allowed values are: 1 12 24 72" ;; + esac + EXPIRE="$1" +} + +add_url() { + if [ "$URLS" = "" ]; then + URLS="$1" + else + URLS+=" $1" + fi + : $(( UPLOAD_COUNT++ )) +} + +copy_urls() { + if ! check_path xsel; then + warn "xsel not found in PATH, not copying URL(s) to clipboard" + return + fi + + if [ "$DISPLAY" = "" ]; then + warn "DISPLAY not set in env, not copying URL(s) to clipboard" + return + fi + + echo -n "$URLS" | xsel -i +} + +# compress_file() gets called on both files and directories. +compress_file() { + local ext + local basefile + local is_dir + + [ -d "$FILE" ] && is_dir=1 + + if [ "$ZIP" = "1" ]; then + ext=.zip + else + ext=.gz + fi + + basefile="$( basename "$FILE" )" + + # TODO: create a random tmp dir, don't use /tmp! + TMPFILE="$TMP/$basefile$ext" + rm -f "$TMPFILE" + if [ "$ZIP" = "1" ]; then + zip -qr "$TMPFILE" "$FILE" + info "zipped $FILE as $TMPFILE" + else + if [ "$is_dir" = 1 ]; then + tar cfz "$TMPFILE" "$FILE" + info "tarred up $FILE as $TMPFILE" + else + gzip -9 < "$FILE" > "$TMPFILE" + info "gzipped $FILE as $TMPFILE" + fi + fi + FILE="$TMPFILE" +} + +# TODO: curl options: +# --max-time --retry --retry-max-time +upload_file() { + local url + local use_compression + + info "checking $FILE" + + case "$FILE" in + *.exe|*.scr|*.cpl|*.doc*|*.jar) + warn "forbidden file extension, compression forced" + use_compression=1 ;; + *.zip|*.gz) + use_compression=0 ;; + *) + use_compression="$COMPRESS" ;; + esac + + if [ "$use_compression" = 1 ]; then + # can't easily zip stdin, write it to a file + if [ "$FILE" = "-" ]; then + FILE="$TMP/$SELF.stdin" + cat > "$FILE" + if [ "$?" != 0 ]; then + rm -f "$FILE" + return + fi + fi + compress_file # resets FILE, sets TMPFILE + fi + + # at this point, we have an actual file, even if input was stdin, + # so we can encrypt it. + if [ "$ENC" = "1" ]; then + CRYPTFILE="$FILE.aes" + openssl enc -pbkdf2 -aes-256-cbc < "$FILE" > "$CRYPTFILE" + if [ "$?" != "0" ]; then + warn "encryption failed, skipping file" + return + fi + FILE="$CRYPTFILE" + fi + + if [ "$URLS" != "" ]; then + delay "uploads" + fi + + info "uploading $FILE" + + url="$( + cat "$FILE" | \ + curl --silent \ + -F "reqtype=fileupload" \ + -F "time=${EXPIRE}h" \ + -F "fileToUpload=@-" \ + "$APIURL" + )" + # TODO: check curl's exit status! + + case "$url" in + https://litter.catbox.moe/*) add_url "$url" ;; + *) warn "upload failed" ;; + esac +} + +download_and_decrypt() { + local url="$1" + info "downloading and decrypting $url" + curl --silent "$url" | openssl enc -d -pbkdf2 -aes-256-cbc + [ "$?" != 0 ] && warn "download/decrypt failed" +} + +# main() +if [ "$1" = "--man" ]; then + manpage ; exit 0 +fi + +if [ "$1" = "--help" ]; then + usage ; exit 0 +fi + +if ! check_path curl; then + die "can't find curl on PATH (PATH is \"$PATH\")" +fi + +# option string starts with a :, meaning we're responsible for +# printing our own error messages. +while getopts ":e:gzcvdo:" OPT; do + case "$OPT" in + e) set_expiration "$OPTARG"; opt_e=1 ;; + o) DLOUT="$OPTARG" ;; + g) GZIP=1 ;; + z) ZIP=1 ;; + c) ENC=1 ;; + v) VERBOSE=1 ;; + d) DOWNLOAD=1 ;; + *) die "invalid option -$OPTARG, try --help" ;; + esac +done + +# getopts doesn't remove the args/options for us, so: +shift $(($OPTIND - 1)) + +# sanity check options and external binaries' existence. +[ "$GZIP" = 1 -a "$ZIP" = 1 ] && die "can't give both -g and -z" + +if [ "$ZIP" = 1 ] && ! check_path zip; then + warn "can't find zip on PATH, disabling -z option" + ZIP=0 +fi + +if [ "$GZIP" = 1 ] && ! check_path gzip; then + warn "can't find gzip on PATH, disabling -g option" + GZIP=0 +fi + +[ "$GZIP" = 1 -o "$ZIP" = 1 ] && COMPRESS=1 + +if [ "$DOWNLOAD" = 1 -o "$ENC" = 1 ]; then + check_path openssl || die "can't find openssl on path, -c/-d won't work" +fi + +# download mode (-d) +if [ "$DOWNLOAD" = 1 ]; then + [ "$GZIP" = 1 ] && warn "-g option ignored when using -d" + [ "$ZIP" = 1 ] && warn "-z option ignored when using -d" + [ "$ENC" = 1 ] && warn "-c option ignored when using -d" + [ "$opt_e" = 1 ] && warn "-e option ignored when using -d" + [ "$DLOUT" != "" ] && exec 1>"$DLOUT" || die "can't redirect stdout" + for arg; do + [ "$need_delay" = "1" ] && delay "downloads" + download_and_decrypt "$arg" + need_delay=1 + done + exit 0 +else + [ "$DLOUT" != "" ] && warn "-o option ignored when not using -d" +fi + +info "expire time set to $( pluralize $EXPIRE hour )" + +# upload mode +[ "$1" = "" ] && set -- - +for arg; do + TMPFILE="" + CRYPTFILE="" + + if [ "$arg" = "-" -o -f "$arg" ]; then + FILE="$arg" + elif [ -d "$arg" ]; then + FILE="$arg" + compress_file # sets FILE + else + # broken symlink, device node, FIFO, ??? + warn "$arg not a regular file, ignoring" + continue + fi + + upload_file + + # clean up if needed + if [ "$TMPFILE" != "" ]; then + info "removing temp file $TMPFILE" + rm -f "$TMPFILE" + fi + + if [ "$TMPFILE" != "" ]; then + info "removing temp encrypted file $CRYPTFILE" + rm -f "$CRYPTFILE" + fi +done + +if [ "$UPLOAD_COUNT" = "0" ]; then + die "no files uploaded" +fi + +echo "$URLS" +copy_urls + +info "$( pluralize $UPLOAD_COUNT file ) uploaded" + +exit 0 + +# Rest of the file is perldoc. +: <<EOF +=pod + +=head1 NAME + +B<litterbox> - upload files to litterbox.catbox.moe + +=head1 SYNOPSIS + +B<litterbox> [-e I<hours>] [-g] [-z] [-c] [-v] I<file> <I<file ...>> + +B<litterbox> -d [-o I<output>] I<url> <I<url ...>> + +=head1 DESCRIPTION + +B<litterbox> uploads files to (or downloads files from) the temporary +file storage site B<https://litterbox.catbox.moe>. The site is +similar to a "pastebin" site, except that it allows any type of +file (not just text), and uploads can be up to 1GB in size. + +=head2 Uploading + +Each I<file> can be a filename, a directory name, or "-" for standard +input. If no files are given, litterbox reads from standard input. +Directories are uploaded as B<.tar.gz> archives, by default. Files +can be optionally encrypted with AES-256. + +Once a file is uploaded, its URL is printed on stdout (one per +line). If B<xsel>(1) is installed and X is running, URLs are also +copied to the X paste buffer (separated by spaces). + +When uploading multiple files, a delay of 2 seconds is added between +uploads, to avoid hammering the site. + +=head2 Downloading + +Download mode is only for downloading AES-256 encrypted files that +were previously uploaded with B<litterbox>. Non-encrypted files can +simply be downloaded with B<wget>(1), B<curl>(1), a web browser, etc. +You will, of course, have to provide the correct decryption key +(password). + +=head1 OPTIONS + +=head2 Upload Options + +=over 4 + +=item B<-e> I<hours> + +Set expiration time in hours. Allowed values are B<1>, B<12>, +B<24>, or B<72>. Default is B<1>. + +=item B<-g> + +Upload gzipped files. This is automatically enabled +when uploading files whose names end in .exe, .scr, +.cpl, .doc*, .jar (unless B<-z> is given). Also, directories +are automatically tarred/gzipped (unless B<-z> is given). + +=item B<-z> + +Upload zipped files or dirs, rather than .gz or .tar.gz. + +=item B<-c> + +Upload encrypted file. Currently this means the file +is encrypted with 'openssl enc -pbkdf2 -aes-256-cbc', and +you're prompted for an encryption key. Whoever downloads +the encrypted file will have to decrypt it with the B<-d> +option, or else do it manually. + +=back + +=head2 Download Options + +=over 4 + +=item B<-d> + +Download and decrypt previously uploaded file(s) from URL(s). +Equivalent to downloading the file normally, then piping it +through: + + openssl enc -d -pbkdf2 -aes-256-cbc + +...which means the file will be printed to your terminal, unless you +use shell redirection or the B<-o> option. The upload options above (B<-e> +B<-g> B<-z> B<-t> B<-c>) are ignored in download mode. + +=item B<-o> I<file> + +Set output file for B<-d> option. Note that giving multiple URLs +will result in all the data being written to the same file. If you need +separate files, run B<litterbox> multiple times. + +The B<-o> option is ignored in upload mode (when B<-d> is not used). + +=back + +=head2 General Options + +=over 4 + +=item B<-v> + +Verbose operation. + +=item B<--help> + +Print this help to standard output and exit. Since the help is long, +it will be passed through your pager. + +=item B<--man> + +Print this help in man page (troff) format to standard output and exit. + +=back + +=head1 NOTES + +=over 2 + +=item B<-> + +B<litter.catbox.moe> is an amazingly useful service. B<Please> be +respectful of the site's owner, B<follow> the site's rules, and don't +abuse the service with excessive requests. You should also consider +supporting the site financially, by buying merch from its store, or +simply making a donation. + +=item B<-> + +With the B<-c> and B<-d> options, you will be prompted interactively +for the encryption key (password), on the process's controlling tty. +This could pose a problem if there's no controlling tty. With +multiple files, you will be prompted separately for each. + +=item B<-> + +Copying URLs to the copy/paste buffer only works under X11. It might +be possible to support gpm(8) for the console. If Wayland has an +xsel-like utility, it could be supported too (the author doesn't use +Wayland so it's not high on the priority list). + +=back + +=head1 AUTHOR + +B. Watson <urchlay@slackware.uk> + +=head1 COPYRIGHT + +B<litterbox> is licensed under the WTFPL: do WTF you want to with this. +See http://www.wtfpl.net/txt/copying/ for details. + +=cut +EOF @@ -1,4 +1,3 @@ #!/bin/sh -VER=${@:-15.0} -exec tmux new elinks http://ftp.osuosl.org/pub/slackware/slackware-$VER/ChangeLog.txt +exec elinks http://ftp.osuosl.org/pub/slackware/slackware-${@:-15.0}/ChangeLog.txt diff --git a/stealvim b/stealvim new file mode 100755 index 0000000..754b02d --- /dev/null +++ b/stealvim @@ -0,0 +1,98 @@ +#!/bin/bash + +SELF="$( basename $0 )" + +warn() { + echo "$SELF: $*" 1>&2 +} + +die() { + echo "$SELF: fatal: $*" 1>&2 + exit 1 +} + +if [ "$1" = "-h" -o "$1" = "--help" -o "$2" != "" ]; then + cat <<EOF +$SELF - take over a running vim instance via reptyr + +Usage: $SELF [<file>} + +With no argument, $SELF searches for .*.swp files in the current +directory. If only one is found, the PID of the process that owns it +is redirected to the current TTY by running "reptyr <pid>". If there +are multiple .*.swp files, no process is redirected; instead the PIDs +that own the files are printed to stderr. + +With a <file> argument, the vim process editing that file (if any) +is passed to reptyr. The <file> can either be the actual file +being edited, or the .*.swp file. + +Typical use case: you were editing a file remotely (via ssh), left +yourself logged in and forgot to exit vim; now you're at the console +or logged in from a different host and want to continue editing the +same file. + +After "stealing" the vim process, it's best to write any changes +and then exit vim immediately. To continue editing, run vim again. +If you ignore this suggestion, things might or might not work OK +depending on the terminal emulators in use, and/or the TERM setting. +EOF +fi + +[ "$( type -p reptyr )" = "" ] && \ + die "reptyr not installed!" + +old="" + +for i in .*.swp; do + [ ! -e "$i" ] && die "no .*.swp files" + + swppid="$( file $i | sed 's/.*, pid \([^,]*\),.*/\1/' )" + + # If there's an argument and we found the matching .swp, use it. + if [ "$i" = "$1" -o "$i" = ".$1.swp" ]; then + pid=$swppid + break + fi + + # If there's an argument and the current .swp file doesn't + # match, ignore this .swp. + [ "$1" != "" ] && continue + + # If the .swp's PID is no longer running, ignore it. + if [ ! -d /proc/$swppid ]; then + warn "$i: PID $swppid no longer running" + continue + fi + + # If we can't read the exe, it likely means it belongs to root, + # or anyway not the current user. + if [ ! -r /proc/$swppid/exe ]; then + warn "$i: PID $swppid doesn't belong to user $( whoami )" + continue + fi + + # If the .swp's PID is running but it's not vim, the PID has been + # reused. ignore it. This works even if vim was called by a + # symlink (e.g. /usr/bin/vi => vim). + case "$( realpath /proc/$swppid/exe )" in + */vim) ;; + *) warn "$i: PID $swppid not a vim process"; continue ;; + esac + + pid=$swppid + if [ "$old" != "" ] && [ "$pid" != "$old" ]; then + die "multiple vim PIDs: $old $pid" + exit 1 + fi + + old=$pid +done + +if [ "$pid" = "" ]; then + msg="no vim PID found" + [ "$1" != "" ] && msg+=" for $1" + die $msg +fi + +reptyr "$pid" @@ -1,16 +1,25 @@ -#!/bin/sh +#!/bin/bash + +VERSION="0.1.0" +SELF="$( basename $0 )" # 20200424 bkw: This used to be a one-line script: # cat "${1:--}" | nc termbin.com 9999 # ...but I really wanted the "copy link to X clipboard" feature. -if [ "$1" = "--help" ]; then +if [ "$1" = "--help" -o "$1" = "-h" ]; then cat <<EOF -Usage: $( basename $0 ) <filename> +termbin v$VERSION + +Usage: $SELF <filename> [<filename> ...] + +Uses nc (netcat) to paste stdin to termbin.com, or pastes one or more +files if <filename(s)> are given. Spits out paste URL on stdout. Also +copies URL to the X clipboard if X is running and either xsel or xclip +is installed. -Uses nc (NetCat) to paste stdin to termbin.com, or pastes a file if -<filename> is given. Spits out paste URL on stdout. Also copies URL to -the X clipboard if X is running and either xsel or xclip is installed. +Only one paste is created. If you give multiple filenames, they are +concatenated together. Written by B. Watson <urchlay@slackware.uk>, released under the WTFPL: do WTF you want with this. @@ -18,20 +27,21 @@ EOF exit 0 fi -if ! which nc &>/dev/null; then - echo "$( basename $0 ): can't find nc on path, install nc or netcat package" - exit 1 -fi +# 20251226 bkw: the sed is because termbin.com sends us e.g. +# https://termbin.com/XXXX\n\0 +# and we get "warning: ignoring null byte" from bash. +url="$( cat "${1:--}" | nc termbin.com 9999 | sed 's,\x00,,' )" -url="$( cat "${1:--}" | nc termbin.com 9999 )" -[ -z "$url" ] && exit "$?" +# 20251227 bkw: don't print an error message if nc fails (nc will print +# its own, or the shell will if it's "command not found"). +err="$?" +[ -z "$url" ] && exit "$err" echo "$url" if [ -n "$DISPLAY" ]; then - if which xsel &>/dev/null; then - echo -n "$url" | xsel -i - elif which xclip &>/dev/null; then - echo -n "$url" | xclip - fi + echo -n "$url" | xsel -i >/dev/null 2>&1 || \ + echo -n "$url" | xclip >/dev/null 2>&1 fi + +exit 0 @@ -0,0 +1,8 @@ +#!/bin/sh + +case "$@" in + -u) PIPE="| unaccent utf8" ;; + *) ;; +esac + +eval exec uconv -x Any-Latin $PIPE @@ -25,9 +25,20 @@ #GLEFT="104x51+1280+0" #GRIGHT="101x51+2222+0" #GFULL="205x51-71+0" -GLEFT="101x49+1280+0" -GRIGHT="90x49+2295+0" -GFULL="191x49+1280+0" + +# Before my Dell widescreen monitor died: +#GLEFT="101x49+1280+0" +#GRIGHT="90x49+2295+0" +#GFULL="191x49+1280+0" + +GLEFT="80x54+1919+0" +GRIGHT="80x54+2720+0" +GFULL="160x54+1920+0" + +# try #100010 for right (dark purple) +CLEFT="-bg #000a00 --color0 #000a00" +CRIGHT="-bg #100010 --color0 #100010" +CFULL="" murder_shell() { # kill the shell that called the shell that's running this script @@ -50,11 +61,11 @@ get_next_geom() { case "$0" in *kill*) murder_shell ;; - *left*) G=$GLEFT ;; - *full*) G=$GFULL ;; + *left*) G=$GLEFT; C="$CLEFT" ;; + *full*) G=$GFULL; C="$CFULL" ;; *next*) G=$( get_next_geom ) ;; - *) G=$GRIGHT ;; + *) G=$GRIGHT; C="$CRIGHT" ;; esac -urxvt -g "$G" "$@" -e sh -c "while true; do bash -login; done" &>/dev/null & +urxvt -g "$G" $C "$@" -e sh -c "while true; do bash -login; done" &>/dev/null & disown @@ -5,7 +5,7 @@ # (c) 2020 B. Watson <urchlay@slackware.uk> # Released under the WTFPL, see http://www.wtfpl.net/txt/copying/ -# Requires xosd. +# Requires aosd_cat (on Slackware, libaosd from SBo). # Intended for use with xbindkeys, like so: #$ cat ~/.xbindkeysrc @@ -20,7 +20,8 @@ # "Next" and "Prior" are PageDown and PageUp. Replace with "Up" and "Down" # to use arrow keys. If you have multimedia keys, you can probably use -# them. See xbindkeys(1). +# them (try XF86AudioRaiseVolume, XF86AudioLowerVolume, and +# XF86AudioMute). See xbindkeys(1). # Can also be used from the command line. Run with no args for help. @@ -33,27 +34,23 @@ CHANNEL=Master # Each up/down adjustment is by this much. Use the dB suffix if you -# prefer decibels, or leave it off for percentage. -ADJ=3dB +# prefer decibels, % percentage, no suffix for raw units (on one of my +# sound cards, the raw unit range is 0 to 87; on another, 0-127). +ADJ=1% -# osd_cat seems a bit picky about what fonts it'll use. If you give a -# nonexistent font, it won't run at all. If you give a font it "doesn't -# like", you'll see the percentage bar, but no "Volume" text. -FONT=12x24 +# Pango font string, see: +# https://docs.gtk.org/Pango/type_func.FontDescription.from_string.html +# The size is in points; 30px would be pixels. +FONT="Mono Normal 30" -# What color is the OSD bar and text? See /usr/share/X11/rgb.txt. +# What color is the OSD bar and text? See /usr/share/X11/rgb.txt, +# or use hex escapes (with #). # COLOR is for when we're unmuted, MUTECOLOR is for muted. -COLOR=orange -MUTECOLOR=red +COLOR='#00ff00' +MUTECOLOR='#ff0000' -# Text drop shadow, 0 to disable. -SHADOW=3 - -# Where does the OSD show up on screen? One of: top middle bottom -POSITION=bottom - -# How long does the OSD persist? In seconds, integer only. -DELAY=2 +# How long does the OSD persist? In milliseconds. +DELAY=2000 # amixer options. Could use -c, -D here. Don't use -q. # default is "-M", see amixer(1). @@ -67,23 +64,43 @@ SELF="$( basename $0 )" PIDFILE="$HOME/.$SELF.osd.pid" -# osd() will kill any previously-spawned osd_cat process. Ideally this +BLOCKS="██████████████████████████████████████████████████" +BLANKS="──────────────────────────────────────────────────" +PARTIAL="▌" + +# progress() prints a UTF-8 progress bar with 50 characters. +# takes a percentage, 0 to 100 +progress() { + local text="$1" + local count="$2" + local solidblocks + local partial + local trailing + + solidblocks="$(( $count / 2 ))" + partial="$(( $count % 2 ))" + trailing="$(( 50 - ( $solidblocks + $partial) ))" + + echo -n "$text${BLOCKS:0:$solidblocks}" + [ "$partial" = "1" ] && echo -n $PARTIAL + echo -n "${BLANKS:0:$trailing}" +} + +# osd() will kill any previously-spawned aosd_cat process. Ideally this # means rapid multiple keypresses won't "step on" each other. In practice # it seems to work OK, but if you press the key really fast on a slow # system, or hold it down with your key-repeat rate cranked up (on any # system), the OSD bar will never get a chance to display. - osd() { local got="$( amixer $AMIXER_OPTS get $CHANNEL | tail -1 )" local muted="$( echo "$got" | grep '\[off\]$' )" local volpct="$( echo "$got" | cut -d'[' -f2 | cut -d% -f1 )" local db="$( echo "$got" | cut -d'[' -f3 | cut -d']' -f1 )" - local text="Volume $db ($volpct%)" local color="$COLOR" + local text="$( printf "%8s" $db) $( printf "%-3s" $volpct% ) " local oldpid if [ -n "$muted" ]; then - text="$text [Muted]" color="$MUTECOLOR" fi @@ -91,18 +108,29 @@ osd() { # files whose PIDs have been recycled. if [ -e $PIDFILE ]; then oldpid="$( cat $PIDFILE )" - grep -q '^osd_cat' /proc/$oldpid/cmdline 2>/dev/null && \ - kill "$oldpid" 2>/dev/null + grep -q '^aosd_cat' /proc/$oldpid/cmdline 2>/dev/null && \ + kill -9 "$oldpid" 2>/dev/null + rm -f $PIDFILE fi - osd_cat -b percentage \ - -d $DELAY \ - -P $volpct \ - -p $POSITION \ - -c $color \ - -s $SHADOW \ - -f $FONT \ - -T "$text" & + # TODO: make these variables in the config section rather than + # hardcoding them. + progress "$text" "$volpct" | \ + aosd_cat \ + --fore-color $color \ + --back-color '#808080' \ + --font "$FONT" \ + --output 1 \ + --x-offset 159 \ + --y-offset 0 \ + --position 7 \ + --transparency 2 \ + --back-opacity 128 \ + --padding 7 \ + --alignment 0 \ + --fade-in 0 \ + --fade-out 0 \ + --fade-full $DELAY & echo "$!" > $PIDFILE } @@ -121,17 +149,17 @@ mute() { usage() { cat <<EOF -$SELF [up|down|mute|<nnn>] +$SELF [up|down|mute|<nn>] -<nnn> is a numeric volume, possibly followed by "dB" and/or "+" or "-". - It will be passed to 'amixer $AMIXER_OPTS set $CHANNEL' as-is. +<nn> is a numeric volume, possibly followed by "dB" or "%", and/or + "+" or "-". It will be passed to 'amixer $AMIXER_OPTS set $CHANNEL' as-is. EOF exit 1 } check_deps() { local missing="no" - for dep in osd_cat amixer; do + for dep in aosd_cat amixer; do if ! type -p "$dep" > /dev/null; then echo "$SELF: missing required executable '$dep'" 1>&2 missing="yes" @@ -157,11 +185,3 @@ esac osd exit 0 - -# For reference: -#$ amixer get Master -#Simple mixer control 'Master',0 -# Capabilities: pvolume pvolume-joined pswitch pswitch-joined -# Playback channels: Mono -# Limits: Playback 0 - 87 -# Mono: Playback 31 [36%] [-42.00dB] [on] |
